astral-sh / uv

An extremely fast Python package and project manager, written in Rust.
https://docs.astral.sh/uv
Apache License 2.0
20k stars 593 forks source link

Multiple indexes without ssl verification #6819

Open jbevi opened 2 weeks ago

jbevi commented 2 weeks ago

uv platform: ubuntu 20 uv version: 0.4.0

Hello, I tell you my case. I currently work with pipenv as a manager of virtual environments in projects.

In my company there is a pypi proxy and other indexes that the different areas use to upload their libraries.

With pipenv I can configure the indexes where to search for the project's libraries and disable ssl validation, as follows.

[pipenv]
install_search_all_sources = true

[[source]]
url = "https://nexus.cloudint.com/nexus/repository/pypi-proxy/simple"
verify_ssl = false
name = "pypi-proxy"

[[source]]
url = "https://nexus.cloudint.comr/nexus/repository/infraestructura-pypi/simple"
verify_ssl = false
name = "infra"

[packages]
fastapi = "==0.111.0"
pyownsecurity = {version = "==2.0.6", index = "infra"}
...

When installing the libraries of a project by doing: pipenv install

It is capable of installing them by searching the configured indexes.

Is there something similar in uv, for example configuring pyproject.toml ? I have tried adding:

[tool.uv]
index-url = "https://nexus.cloudint.com/nexus/repository/pypi-proxy/simple/"
extra-index-url = ["https://nexus.cloudint.com/nexus/repository/infrastructure-pypi/simple/"]

When doing uv add uvicorn for example, it tries to search for the library in the extra-index-url, but not in index-url, which is where it is located, and it gives an ssl validation error. Log extract:

retrying: error sending request for url (https://nexus.cloudint.com/nexus/repository/infraestructura-pypi/simple/uvicorn/) Caused by: client error (Connect) Caused by: received fatal alert: HandshakeFailure error: Request failed after 3 retries Caused by: error sending request for url (https://nexus.cloudint.com/nexus/repository/infraestructura-pypi/simple/uvicorn/) Caused by: client error (Connect) Caused by: received fatal alert: HandshakeFailure

Thanks in advance.

zanieb commented 2 weeks ago

Hi! Do you mind reading these to see if they address your questions?

jbevi commented 2 weeks ago

I tried adding to pyproject.toml:

[tool.uv] allow-insecure-host = ["nexus.cloudint.com"]

but it seems to have no effect and the handshake error continues.

charliermarsh commented 2 weeks ago

Can you run a command with --show-settings, and see if the setting is being picked up properly?

jbevi commented 2 weeks ago
uv add uvicorn --show-settings
GlobalSettings {
    quiet: false,
    verbose: 0,
    color: Auto,
    native_tls: false,
    concurrency: Concurrency {
        downloads: 50,
        builds: 8,
        installs: 8,
    },
    connectivity: Online,
    show_settings: true,
    preview: Disabled,
    python_preference: Managed,
    python_downloads: Automatic,
    no_progress: false,
}
CacheSettings {
    no_cache: false,
    cache_dir: None,
}
AddSettings {
    locked: false,
    frozen: false,
    no_sync: false,
    packages: [
        "uvicorn",
    ],
    requirements: [],
    dependency_type: Production,
    editable: None,
    extras: [],
    raw_sources: false,
    rev: None,
    tag: None,
    branch: None,
    package: None,
    script: None,
    python: None,
    refresh: None(
        Timestamp(
            SystemTime {
                tv_sec: 1724954621,
                tv_nsec: 41840693,
            },
        ),
    ),
    settings: ResolverInstallerSettings {
        index_locations: IndexLocations {
            index: None,
            extra_index: [
                Url(
                    VerbatimUrl {
                        url: Url {
                            scheme: "https",
                            cannot_be_a_base: false,
                            username: "",
                            password: None,
                            host: Some(
                                Domain(
                                    "nexus.cloudint.com",
                                ),
                            ),
                            port: None,
                            path: "/nexus/repository/pypi-proxy/simple",
                            query: None,
                            fragment: None,
                        },
                        given: Some(
                            "https://nexus.cloudint.com/nexus/repository/pypi-proxy/simple",
                        ),
                    },
                ),
                Url(
                    VerbatimUrl {
                        url: Url {
                            scheme: "https",
                            cannot_be_a_base: false,
                            username: "",
                            password: None,
                            host: Some(
                                Domain(
                                    "nexus.cloudint.com",
                                ),
                            ),
                            port: None,
                            path: "/nexus/repository/infraestructura-pypi/simple/",
                            query: None,
                            fragment: None,
                        },
                        given: Some(
                            "https://nexus.cloudint.com/nexus/repository/infraestructura-pypi/simple/",
                        ),
                    },
                ),
            ],
            flat_index: [],
            no_index: false,
        },
        index_strategy: FirstIndex,
        keyring_provider: Disabled,
        allow_insecure_host: [
            TrustedHost {
                scheme: Some(
                    "https",
                ),
                host: "nexus.cloudint.com",
                port: None,
            },
        ],
        resolution: Highest,
        prerelease: IfNecessaryOrExplicit,
        config_setting: ConfigSettings(
            {},
        ),
        no_build_isolation: false,
        no_build_isolation_package: [],
        exclude_newer: None,
        link_mode: Hardlink,
        compile_bytecode: false,
        sources: Enabled,
        upgrade: None,
        reinstall: None,
        build_options: BuildOptions {
            no_binary: None,
            no_build: None,
        },
    },
}
zanieb commented 2 weeks ago

Interesting, that all looks correct.

charliermarsh commented 2 weeks ago

I suspect that your server is misconfigured in some other way... When the certificate is invalid, you tend to get invalid peer certificate?

djc commented 2 weeks ago

Do you know what software is being used to run the PyPI proxy? I tried to connect to nexus.cloudint.com but I suppose that it is internal only. A packet capture might help a little but we'd probably need to setup SSLKEYLOGFILE support which I guess uv might not support out of the box.

ctz commented 2 weeks ago

This is unlikely to be related to the server certificate. Instead, the server does not have any overlap with the client's TLS settings, so it sends a TLS alert saying a handshake is impossible. That is the "received fatal alert: HandshakeFailure" output; the client doesn't get any more information than this.

Suggest running a local tool like sslscan against the host to see what TLS versions and cipher suites it does support.

jbevi commented 2 weeks ago

Thanks for the quick responses. I don't have the option to run sslscan on the server. My main doubt is why this error occurs with UV, but not with pipenv, pip, or even curl.

djc commented 2 weeks ago

No, you'd run sslscan on the client, against the server.

jbevi commented 2 weeks ago

I'm not allowed to do that. But I can run curl using the index url:

curl https://nexus.cloudint.com/nexus/repository/pypi-proxy/simple/uvicorn/ -v

I write the log extracts:

...
Connected to nexus.cloudint.com port 443 (#0)
...
SSL connection using TLSv1.2
...
HTTP/1.1 200 OK
...
<html lang="en">
<head><title>Links for uvicor</title>
  <meta name="api-version" value="2"/>
</head>
<body><h1>Links for uvicor</h1>
        <a href="../../packages/uvicorn/0.0.1/uvicorn-0.0.1.tar.gz#sha256=a88750101a094e293ed543f750e78be9fa00594966d32a7805b9d93fa0f9cdd5" rel="internal">uvicorn-0.0.1.tar.gz</a><br/>
....