Skip to content

Conversation

@tdejager
Copy link
Contributor

@tdejager tdejager commented Dec 1, 2025

Description

uv allows loading of the system certificate instead of the ones provided by default for rustls. This changes the code to have a native_certs configuration option (global) and CLI options so that one can opt-in to the system store. This all still uses rustls under the hood. This was apparently a much-requested feature for uv. Luckily we can just change the client construction implementation and enable this for both conda and PyPI network requests.

I used a different name and construction and deviated from uv here, because we have different requirements. We have both native-tls (conda-forge) builds, and non-native tls. So I added the option for the use to be able to choose, what root certificates to load. For example, when running pixi install --help, you get:

...
      --tls-root-certs <TLS_ROOT_CERTS>
          Which TLS root certificates to use: 'webpki' (bundled Mozilla roots), 'native' (system store), or 'all' (both)

          [env: PIXI_TLS_ROOT_CERTS=]

There is also a corresponding pixi_config global setting. That can be set if need be.

By default the rustls version uses only "webpki", and the native-tls uses the system store, for rustls you can use "webpki", "native" or "all". For the native-tls version the methods, tls_built_in_webpki_certs and tls_built_in_native_certs should not be available, i.e. these are only available for rustls. So we give a warning in this case that these options will be ignored. See: https://docs.rs/reqwest/latest/reqwest/struct.ClientBuilder.html#method.tls_built_in_webpki_certs

However, and this is a question for @baszalmstra, I feel these will actually be available on our native-tls build; because of uv ensuring that both features are enabled, as they support only rustls and in the case of a conda-forge build, both features will be on. Not sure what do here but opted to go for the "most correct" approach. wdyt?

Fixes #4896

How Has This Been Tested?

I have a script made in scripts/test_native_cert.py and corresponding pixi tasks to check if this works. Run pixi r build-release and pixi run test-native-certs to verify. This sets up a PyPI registry ngnix docker with a generated CA we add this to the system store to see if we can connect with it.

Maybe the OP of the issue could give it a go as well.

AI Disclosure

  • This PR contains AI-generated content.
    • I have tested any AI-generated content in my PR.
    • I take responsibility for any AI-generated content in my PR.

Tools: Claude Opus 4.5

Checklist:

  • I have performed a self-review of my own code
  • I have commented my code, particularly in hard-to-understand areas
  • I have made corresponding changes to the documentation
  • I have added sufficient tests to cover my changes.
  • I have verified that changes that would impact the JSON schema have been made in schema/model.py.

@tdejager tdejager requested review from baszalmstra and wolfv December 1, 2025 09:13
Copy link
Contributor

@baszalmstra baszalmstra left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice, how do we deal with this on conda-forge where we use nativetls instead?

@tdejager
Copy link
Contributor Author

tdejager commented Dec 1, 2025

Nice, how do we deal with this on conda-forge where we use nativetls instead?

Hmm maybe we should remove it for those builds, as this config does not make sense. Wdyt?

@baszalmstra
Copy link
Contributor

maybe we could have a config called tls-certs which is webpki or native. And we have different defaults based on the selected feature?

@tdejager
Copy link
Contributor Author

tdejager commented Dec 1, 2025 via email

@tdejager
Copy link
Contributor Author

tdejager commented Dec 1, 2025

maybe we could have a config called tls-certs which is webpki or native. And we have different defaults based on the selected feature?

I implemented a version of this @baszalmstra but an open question still remains :)

#[serde(rename_all = "lowercase")]
pub enum TlsRootCerts {
/// Use bundled Mozilla root certificates
#[default]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This default depends on which backend is selected through features.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well the config just doesn't do anything because there is not really an option to select it for native-tls, like the methods to select webkpi are compiled out. So the config is only there in both compilation features as to not break on your config when you switch.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Crazy

@baszalmstra
Copy link
Contributor

However, and this is a question for @baszalmstra, I feel these will actually be available on our native-tls build; because of uv ensuring that both features are enabled, as they support only rustls and in the case of a conda-forge build, both features will be on. Not sure what do here but opted to go for the "most correct" approach. wdyt?

Makes sense to me, we can always change this later.

@jamblejoe
Copy link

jamblejoe commented Dec 2, 2025

OP here. I ran test_native_certs.py successfully and got

./target/release/pixi run python scripts/test_native_certs.py --pixi-bin ./target/release/pixi
╭───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│ TLS Root Certs Feature Test                                                                                                                                                                                               │
╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
Test directory: /var/folders/hv/3wt4f9r11dz935gtp9fjmsgm0000gp/T/pixi-native-certs-3nx9vq14
Setting up mkcert CA...
The local CA is already installed in the system trust store! 👍
Warning: "certutil" is not available, so the CA can't be automatically installed in Firefox! ⚠️
Install "certutil" with "brew install nss" and re-run "mkcert -install" 👈

✓ mkcert CA installed in system trust store
Generating certificates...
Note: the local CA is not installed in the Firefox trust store.
Run "mkcert -install" for certificates to be trusted automatically ⚠️

Created a new certificate valid for the following names 📜
 - "localhost"
 - "127.0.0.1"

The certificate is at "/var/folders/hv/3wt4f9r11dz935gtp9fjmsgm0000gp/T/pixi-native-certs-3nx9vq14/cert.pem" and the key at "/var/folders/hv/3wt4f9r11dz935gtp9fjmsgm0000gp/T/pixi-native-certs-3nx9vq14/key.pem" ✅

It will expire on 2 March 2028 🗓

✓ Certificates generated
Creating test package...
✓ Test package created
Creating PyPI simple index...
✓ Simple index created
Starting HTTPS PyPI server...
✓ PyPI server running at https://localhost:62686
Creating test pixi project...
✓ Test project created
╭───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│ Running Tests                                                                                                                                                                                                             │
╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯

Test A: With tls-root-certs=webpki (should FAIL)
The CA is NOT in webpki-roots, so this should fail

✓ Test A PASSED: Got expected certificate error

Test B: With tls-root-certs=native (should SUCCEED)
The CA IS in the system trust store, so this should work

✓ Test B PASSED: Install succeeded with native certs
╭───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│ Test Summary                                                                                                                                                                                                              │
╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
All tests PASSED!

The tls-root-certs feature is working correctly:
  - tls-root-certs=webpki: Uses webpki-roots (mkcert CA not trusted)
  - tls-root-certs=native: Uses system store (mkcert CA trusted)
Cleaned up test directory

@tdejager
Copy link
Contributor Author

tdejager commented Dec 3, 2025

OP here. I ran test_native_certs.py successfully and got

./target/release/pixi run python scripts/test_native_certs.py --pixi-bin ./target/release/pixi
╭───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│ TLS Root Certs Feature Test                                                                                                                                                                                               │
╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
Test directory: /var/folders/hv/3wt4f9r11dz935gtp9fjmsgm0000gp/T/pixi-native-certs-3nx9vq14
Setting up mkcert CA...
The local CA is already installed in the system trust store! 👍
Warning: "certutil" is not available, so the CA can't be automatically installed in Firefox! ⚠️
Install "certutil" with "brew install nss" and re-run "mkcert -install" 👈

✓ mkcert CA installed in system trust store
Generating certificates...
Note: the local CA is not installed in the Firefox trust store.
Run "mkcert -install" for certificates to be trusted automatically ⚠️

Created a new certificate valid for the following names 📜
 - "localhost"
 - "127.0.0.1"

The certificate is at "/var/folders/hv/3wt4f9r11dz935gtp9fjmsgm0000gp/T/pixi-native-certs-3nx9vq14/cert.pem" and the key at "/var/folders/hv/3wt4f9r11dz935gtp9fjmsgm0000gp/T/pixi-native-certs-3nx9vq14/key.pem" ✅

It will expire on 2 March 2028 🗓

✓ Certificates generated
Creating test package...
✓ Test package created
Creating PyPI simple index...
✓ Simple index created
Starting HTTPS PyPI server...
✓ PyPI server running at https://localhost:62686
Creating test pixi project...
✓ Test project created
╭───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│ Running Tests                                                                                                                                                                                                             │
╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯

Test A: With tls-root-certs=webpki (should FAIL)
The CA is NOT in webpki-roots, so this should fail

✓ Test A PASSED: Got expected certificate error

Test B: With tls-root-certs=native (should SUCCEED)
The CA IS in the system trust store, so this should work

✓ Test B PASSED: Install succeeded with native certs
╭───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│ Test Summary                                                                                                                                                                                                              │
╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
All tests PASSED!

The tls-root-certs feature is working correctly:
  - tls-root-certs=webpki: Uses webpki-roots (mkcert CA not trusted)
  - tls-root-certs=native: Uses system store (mkcert CA trusted)
Cleaned up test directory

Would you be able to check if with the version of pixi compiled from this branch you are able to reach your index? :)

@tdejager tdejager marked this pull request as ready for review December 3, 2025 09:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

pixis internal uv does not recognize UV_NATIVE_TLS env variable

3 participants