pip icon indicating copy to clipboard operation
pip copied to clipboard

Using a private package index with pip 24.2 results in `ValueError: check_hostname requires server_hostname`

Open hoel-bagard opened this issue 1 year ago • 6 comments

Description

Attempting to install a package from a private package index with pip 24.2 results in a ValueError: check_hostname requires server_hostname error.

I am using the command below:

pip install <package name> --index-url=<private package index>

Expected behavior

Package is downloaded from the index without an error occuring.

pip version

24.2

Python version

3.12

OS

Linux

How to Reproduce

  1. Install pip: pip install pip==24.2
  2. Try to install a package from the private index. For example with pip install pip==24.1 --index-url=https://163.219.218.169/root/pypi --no-cache-dir
  3. The ValueError: check_hostname requires server_hostname exception occurs.

Output

Full traceback
WARNING: There was an error checking the latest version of pip.
ERROR: Exception:
Traceback (most recent call last):
  File "/home/hoel/work-hitachi/pypi-repository/.venv/lib/python3.12/site-packages/pip/_internal/cli/base_command.py", line 105, in _run_wrapper
    status = _inner_run()
             ^^^^^^^^^^^^
  File "/home/hoel/work-hitachi/pypi-repository/.venv/lib/python3.12/site-packages/pip/_internal/cli/base_command.py", line 96, in _inner_run
    return self.run(options, args)
           ^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/hoel/work-hitachi/pypi-repository/.venv/lib/python3.12/site-packages/pip/_internal/cli/req_command.py", line 67, in wrapper
    return func(self, options, args)
           ^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/hoel/work-hitachi/pypi-repository/.venv/lib/python3.12/site-packages/pip/_internal/commands/install.py", line 379, in run
    requirement_set = resolver.resolve(
                      ^^^^^^^^^^^^^^^^^
  File "/home/hoel/work-hitachi/pypi-repository/.venv/lib/python3.12/site-packages/pip/_internal/resolution/resolvelib/resolver.py", line 95, in resolve
    result = self._result = resolver.resolve(
                            ^^^^^^^^^^^^^^^^^
  File "/home/hoel/work-hitachi/pypi-repository/.venv/lib/python3.12/site-packages/pip/_vendor/resolvelib/resolvers.py", line 546, in resolve
    state = resolution.resolve(requirements, max_rounds=max_rounds)
            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/hoel/work-hitachi/pypi-repository/.venv/lib/python3.12/site-packages/pip/_vendor/resolvelib/resolvers.py", line 397, in resolve
    self._add_to_criteria(self.state.criteria, r, parent=None)
  File "/home/hoel/work-hitachi/pypi-repository/.venv/lib/python3.12/site-packages/pip/_vendor/resolvelib/resolvers.py", line 173, in _add_to_criteria
    if not criterion.candidates:
           ^^^^^^^^^^^^^^^^^^^^
  File "/home/hoel/work-hitachi/pypi-repository/.venv/lib/python3.12/site-packages/pip/_vendor/resolvelib/structs.py", line 156, in __bool__
    return bool(self._sequence)
           ^^^^^^^^^^^^^^^^^^^^
  File "/home/hoel/work-hitachi/pypi-repository/.venv/lib/python3.12/site-packages/pip/_internal/resolution/resolvelib/found_candidates.py", line 174, in __bool__
    return any(self)
           ^^^^^^^^^
  File "/home/hoel/work-hitachi/pypi-repository/.venv/lib/python3.12/site-packages/pip/_internal/resolution/resolvelib/found_candidates.py", line 162, in <genexpr>
    return (c for c in iterator if id(c) not in self._incompatible_ids)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/hoel/work-hitachi/pypi-repository/.venv/lib/python3.12/site-packages/pip/_internal/resolution/resolvelib/found_candidates.py", line 49, in _iter_built
    for version, func in infos:
  File "/home/hoel/work-hitachi/pypi-repository/.venv/lib/python3.12/site-packages/pip/_internal/resolution/resolvelib/factory.py", line 301, in iter_index_candidate_infos
    result = self._finder.find_best_candidate(
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/hoel/work-hitachi/pypi-repository/.venv/lib/python3.12/site-packages/pip/_internal/index/package_finder.py", line 883, in find_best_candidate
    candidates = self.find_all_candidates(project_name)
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/hoel/work-hitachi/pypi-repository/.venv/lib/python3.12/site-packages/pip/_internal/index/package_finder.py", line 824, in find_all_candidates
    page_candidates = list(page_candidates_it)
                      ^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/hoel/work-hitachi/pypi-repository/.venv/lib/python3.12/site-packages/pip/_internal/index/sources.py", line 194, in page_candidates
    yield from self._candidates_from_page(self._link)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/hoel/work-hitachi/pypi-repository/.venv/lib/python3.12/site-packages/pip/_internal/index/package_finder.py", line 784, in process_project_url
    index_response = self._link_collector.fetch_response(project_url)
                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/hoel/work-hitachi/pypi-repository/.venv/lib/python3.12/site-packages/pip/_internal/index/collector.py", line 448, in fetch_response
    return _get_index_content(location, session=self.session)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/hoel/work-hitachi/pypi-repository/.venv/lib/python3.12/site-packages/pip/_internal/index/collector.py", line 352, in _get_index_content
    resp = _get_simple_response(url, session=session)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/hoel/work-hitachi/pypi-repository/.venv/lib/python3.12/site-packages/pip/_internal/index/collector.py", line 131, in _get_simple_response
    resp = session.get(
           ^^^^^^^^^^^^
  File "/home/hoel/work-hitachi/pypi-repository/.venv/lib/python3.12/site-packages/pip/_vendor/requests/sessions.py", line 602, in get
    return self.request("GET", url, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/hoel/work-hitachi/pypi-repository/.venv/lib/python3.12/site-packages/pip/_internal/network/session.py", line 522, in request
    return super().request(method, url, *args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/hoel/work-hitachi/pypi-repository/.venv/lib/python3.12/site-packages/pip/_vendor/requests/sessions.py", line 589, in request
    resp = self.send(prep, **send_kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/hoel/work-hitachi/pypi-repository/.venv/lib/python3.12/site-packages/pip/_vendor/requests/sessions.py", line 703, in send
    r = adapter.send(request, **kwargs)
        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/hoel/work-hitachi/pypi-repository/.venv/lib/python3.12/site-packages/pip/_vendor/requests/adapters.py", line 667, in send
    resp = conn.urlopen(
           ^^^^^^^^^^^^^
  File "/home/hoel/work-hitachi/pypi-repository/.venv/lib/python3.12/site-packages/pip/_vendor/urllib3/connectionpool.py", line 715, in urlopen
    httplib_response = self._make_request(
                       ^^^^^^^^^^^^^^^^^^^
  File "/home/hoel/work-hitachi/pypi-repository/.venv/lib/python3.12/site-packages/pip/_vendor/urllib3/connectionpool.py", line 404, in _make_request
    self._validate_conn(conn)
  File "/home/hoel/work-hitachi/pypi-repository/.venv/lib/python3.12/site-packages/pip/_vendor/urllib3/connectionpool.py", line 1058, in _validate_conn
    conn.connect()
  File "/home/hoel/work-hitachi/pypi-repository/.venv/lib/python3.12/site-packages/pip/_vendor/urllib3/connection.py", line 419, in connect
    self.sock = ssl_wrap_socket(
                ^^^^^^^^^^^^^^^^
  File "/home/hoel/work-hitachi/pypi-repository/.venv/lib/python3.12/site-packages/pip/_vendor/urllib3/util/ssl_.py", line 453, in ssl_wrap_socket
    ssl_sock = _ssl_wrap_socket_impl(sock, context, tls_in_tls)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/hoel/work-hitachi/pypi-repository/.venv/lib/python3.12/site-packages/pip/_vendor/urllib3/util/ssl_.py", line 495, in _ssl_wrap_socket_impl
    return ssl_context.wrap_socket(sock)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/hoel/work-hitachi/pypi-repository/.venv/lib/python3.12/site-packages/pip/_vendor/truststore/_api.py", line 96, in wrap_socket
    ssl_sock = self._ctx.wrap_socket(
               ^^^^^^^^^^^^^^^^^^^^^^
  File "/home/hoel/.pyenv/versions/3.12.3/lib/python3.12/ssl.py", line 455, in wrap_socket
    return self.sslsocket_class._create(
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/hoel/.pyenv/versions/3.12.3/lib/python3.12/ssl.py", line 970, in _create
    raise ValueError("check_hostname requires server_hostname")
ValueError: check_hostname requires server_hostname

Other

I am still in the process of setting up the https part of my private package index, and while I was able to use it to some extend with pip==24.1, I had to manually point to the CA certificate. So I cannot exclude the possibility of a wrong setup on my part.

$ pip install pip==24.2 --index-url=https://163.219.218.169/root/pypi --no-cache-dir --use-feature=truststore
Could not Could not fetch URL https://163.219.218.169/root/pypi/pip/: There was a problem confirming the ssl certificate: HTTPSConnectionPool(host='163.219.218.169', port=443): Max retries exceeded with url: /root/pypi/pip/ (Caused by SSLError(SSLCertVerificationError(1, '[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: self signed certificate in certificate chain (_ssl.c:1000)'))) - skipping
$ pip install pip==24.2 --index-url=https://163.219.218.169/root/pypi --no-cache-dir --cert assets/ca.pem
Successfully installed pip-24.2

Code of Conduct

hoel-bagard avatar Aug 09 '24 06:08 hoel-bagard

Could you try passing --use-deprecated=legacy-certs to the pip invocation? If that works, then we can narrow down the issue to the truststore feature (which seems likely given that pip 24.1 works which has truststore disabled by default). cc @sethmlarson

ichard26 avatar Aug 09 '24 16:08 ichard26

I wasn't able to get the ValueError you're running into to reproduce, is there any other flag you're passing to pip or environment variable that would configure/disable certificate verification?

I tried using TestPyPI as an example "index-url", maybe it only triggers for other indices?

$ python -m pip --version
pip 24.2 from /tmp/pip-12906/venv/lib/python3.12/site-packages/pip (python 3.12)

$ python -m pip install urllib3 --index-url=https://test.pypi.org/simple --no-cache-dir
(succeeds)

sethmlarson avatar Aug 09 '24 20:08 sethmlarson

Could you try passing --use-deprecated=legacy-certs to the pip invocation? If that works, then we can narrow down the issue to the truststore feature (which seems likely given that pip 24.1 works which has truststore disabled by default).

If I use --use-deprecated=legacy-certs, then the behavior becomes the same as with pip 24.1. It works if I give the pass to the CA using --cert (I guess that's because I haven't configured things properly, although I don't know what I'm missing).

I wasn't able to get the ValueError you're running into to reproduce, is there any other flag you're passing to pip or environment variable that would configure/disable certificate verification?

Not that I'm aware of. I saw in this issue that it got linked to proxy settings. I am behind a proxy, however I am unsetting all the proxy environment variable when running the pip commands (since the private index is in the local network).

I tried using TestPyPI as an example "index-url", maybe it only triggers for other indices?

I tried your command, and it worked without issue. I'm not sure how relevant it is, but I set the proxy environment variables when doing it. I'll try to replicate the issue in a simplified environment.

hoel-bagard avatar Aug 10 '24 01:08 hoel-bagard

(I guess that's because I haven't configured things properly, although I don't know what I'm missing).

Well, before pip 24.2, pip would only verify certificates against its vendored certificate bundle. That's what certifi is: it's a Python repackaging of Mozilla's certificate bundle. For a while, pip gained the ability to integrate with truststore which uses the system certificate store. However, this feature was disabled by default and had to be enabled manually until pip 24.2. In theory, "it should just work" if your private CA is configured properly at the system level with truststore enabled, but evidently somewhere in the chain (:P) it's not working...

A simplified or MRE would be greatly appreciated.

ichard26 avatar Aug 14 '24 17:08 ichard26

@ichard26 I've been able to reproduce the error using this repo.

I ran it at home on my personal computer, so no proxy was involved.

hoel-bagard avatar Aug 16 '24 04:08 hoel-bagard

@sethmlarson while I have your attention, perhaps you could look at this too? :)

There is an attached reproduction repository, but I was able to reproduce the error by simply pointing pip to a 127.0.0.1 HTTPS index with a custom CA/cert. I wasn't able to figure out what exactly goes wrong, but it seems like with truststore enabled, the check_hostname session attribute remains true despite urllib3 attempting to disable it.

ichard26 avatar Aug 21 '24 18:08 ichard26

Heya, any updates @sethmlarson? It's too late for the 24.3 cycle, but I'd love to make truststore rock solid on supported platforms in pip 25.0.

ichard26 avatar Oct 26 '24 16:10 ichard26

I haven't dug into this issue recently, but the latest release of truststore did make some changes to check_hostname, might be worth checking again.

sethmlarson avatar Oct 26 '24 21:10 sethmlarson

I'm seeing this error also with a self-signed root CA and private PyPi registry. Usually setting PIP_CERT works, but not with v24.2 and v24.3. I keep getting a ValueError: check_hostname requires server_hostname error.

File "/server-082/workspace/project-ea52f8/venv/lib/python3.12/site-packages/pip/_vendor/truststore/_api.py", line 96, in wrap_socket
    ssl_sock = self._ctx.wrap_socket(
               ^^^^^^^^^^^^^^^^^^^^^^
  File "/opt/tools/Python/3.12.7/x64/lib/python3.12/ssl.py", line 455, in wrap_socket
    return self.sslsocket_class._create(
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/opt/tools/Python/3.12.7/x64/lib/python3.12/ssl.py", line 969, in _create
    raise ValueError("check_hostname requires server_hostname")
ValueError: check_hostname requires server_hostname

rob4226 avatar Oct 28 '24 08:10 rob4226