Skip to content

Expand environment variables in user-provided index URLs#13879

Open
msabramo wants to merge 5 commits intoastral-sh:mainfrom
msabramo:env-vars-in-index-urls
Open

Expand environment variables in user-provided index URLs#13879
msabramo wants to merge 5 commits intoastral-sh:mainfrom
msabramo:env-vars-in-index-urls

Conversation

@msabramo
Copy link

@msabramo msabramo commented Jun 6, 2025

Fixes: GH-5734

Summary

This PR adds support for environment variable expansion in [[tool.uv.index]] configuration URLs, enabling dynamic and secure index configuration.

What it does:

  • Expands environment variables in url and publish-url fields using ${VARIABLE} and ${VARIABLE:-default} syntax
  • Supports tilde (~) expansion for home directory paths
  • Enables secure credential injection without storing sensitive information in plaintext configuration files
  • Allows for environment-specific configuration (dev/staging/prod) using the same pyproject.toml

Implementation details:

  • Added shellexpand crate dependency for robust environment variable and tilde expansion
  • Implemented custom Deserialize for the Index struct to perform expansion during TOML parsing
  • Added comprehensive error handling with descriptive messages for missing variables or expansion failures
  • Maintains backward compatibility with existing configurations

Example usage:

[[tool.uv.index]]
name = "artifactory"
url = "https://${ARTIFACTORY_USER}:${ARTIFACTORY_API_TOKEN}@artifactory.company.com/simple"

Test Plan

Unit tests:

  • test_index_environment_variable_expansion: Verifies ${VAR} syntax expansion with set environment variables
  • test_index_without_environment_variables: Ensures existing configurations without env vars continue to work
  • test_index_missing_environment_variable: Tests error handling when required environment variables are missing
  • test_index_tilde_expansion: Verifies ~ home directory expansion works correctly

Integration testing:

  • Ran /Users/abramowi/Code/OpenSource/uv/target/release/uv sync in a project that had something like:
    [[tool.uv.index]]
    name = "artifactory"
    url = "https://${ARTIFACTORY_USER}:${ARTIFACTORY_API_TOKEN}@artifactory.company.com/artifactory/api/pypi/pypi-colorado-tools-snapshot/simple"
    
  • Ran a normal uv sync which failed:
$ uv sync -v | grep artifactory
...
  × Failed to download `vortex-sdk==0.0.35`
  ├─▶ Failed to fetch:
  │   `https://artifactory.company.com/artifactory/api/pypi/pypi-colorado-tools-snapshot/vortex-sdk/0.0.35/vortex_sdk-0.0.35-py3-none-any.whl`
  ╰─▶ HTTP status client error (401 Unauthorized) for url
      (https://artifactory.company.com/artifactory/api/pypi/pypi-colorado-tools-snapshot/vortex-sdk/0.0.35/vortex_sdk-0.0.35-py3-none-any.whl)
  • Built uv from this branch with cargo build --release
  • Ran $ /Users/abramowi/Code/OpenSource/uv/target/release/uv sync -v | grep artifactory and got:
DEBUG No cache entry for: https://artifactory.company.com/artifactory/api/pypi/pypi-colorado-tools-snapshot/vortex-sdk/0.0.35/vortex_sdk-0.0.35-py3-none-any.whl
Prepared 1 package in 469ms
Installed 1 package in 3ms
 + vortex-sdk==0.0.35

Compatibility testing:

  • All existing cargo test -p uv-distribution-types tests pass
    abramowi at marcs-mbp-3 in ~/Code/OpenSource/uv (env-vars-in-index-urls●)
    $ cargo test -p uv-distribution-types
    ...
    test result: ok. 19 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
    
  • No breaking changes to existing index configurations
  • Error messages are clear and actionable when environment variables are missing

Documentation:

  • Updated docs/concepts/indexes.md with environment variable expansion section and examples
  • Enhanced docs/guides/integration/alternative-indexes.md with env var examples for Azure, GCP, and AWS
  • Updated docs/reference/settings.md with comprehensive examples and feature description

@msabramo msabramo marked this pull request as draft June 6, 2025 05:11
@msabramo msabramo force-pushed the env-vars-in-index-urls branch from e2f68b3 to 1dbd9ec Compare June 6, 2025 05:12
@msabramo msabramo marked this pull request as ready for review June 6, 2025 05:12
@msabramo msabramo force-pushed the env-vars-in-index-urls branch from 1dbd9ec to 65ad2bd Compare June 6, 2025 05:14
@msabramo msabramo marked this pull request as draft June 6, 2025 05:16
@msabramo msabramo force-pushed the env-vars-in-index-urls branch from 65ad2bd to acf7189 Compare June 6, 2025 05:18
by running `cargo dev generate-options-reference`
@msabramo
Copy link
Author

msabramo commented Jun 6, 2025

Windows test failed with what looks to be an intermittent failure downloading Python:

    ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Snapshot Summary ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
    Snapshot: python_install_preview-10
    Source: D:\uv:463
    ───────────────────────────────────────────────────────────────────────────────
    Expression: snapshot
    ───────────────────────────────────────────────────────────────────────────────
    -old snapshot
    +new results
    ────────────┬──────────────────────────────────────────────────────────────────
        0       │-success: true
        1       │-exit_code: 0
              0 │+success: false
              1 │+exit_code: 1
        2     2 │ ----- stdout -----
        3     3 │ 
        4     4 │ ----- stderr -----
        5       │-Installed 2 versions in [TIME]
        6       │- + cpython-3.12.6-[PLATFORM]
        7       │- + cpython-3.12.8-[PLATFORM] (python3.12)
              5 │+Installed Python 3.12.6 in [TIME]
              6 │+ + cpython-3.12.6-[PLATFORM] (python3.12)
              7 │+error: Failed to install cpython-3.12.8-[PLATFORM]
              8 │+  Caused by: Failed to download https://github.com/astral-sh/python-build-standalone/releases/download/20250115/cpython-3.12.8%2B20250115-x86_64-pc-windows-msvc-install_only_stripped.tar.gz
              9 │+  Caused by: HTTP status server error (500 Internal Server Error) for url (https://github.com/astral-sh/python-build-standalone/releases/download/20250115/cpython-3.12.8%2B20250115-x86_64-pc-windows-msvc-install_only_stripped.tar.gz)
    ────────────┴──────────────────────────────────────────────────────────────────
    Stopped on the first failure. Run `cargo insta test` to run all snapshots.
    test python_install::python_install_preview ... FAILED

to see if failing Windows GitHub action passes this time.
@msabramo msabramo marked this pull request as ready for review June 6, 2025 12:56
@msabramo
Copy link
Author

msabramo commented Jun 6, 2025

Windows test failed with what looks to be an intermittent failure downloading Python:

    ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Snapshot Summary ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
    Snapshot: python_install_preview-10
    Source: D:\uv:463
    ───────────────────────────────────────────────────────────────────────────────
    Expression: snapshot
    ───────────────────────────────────────────────────────────────────────────────
    -old snapshot
    +new results
    ────────────┬──────────────────────────────────────────────────────────────────
        0       │-success: true
        1       │-exit_code: 0
              0 │+success: false
              1 │+exit_code: 1
        2     2 │ ----- stdout -----
        3     3 │ 
        4     4 │ ----- stderr -----
        5       │-Installed 2 versions in [TIME]
        6       │- + cpython-3.12.6-[PLATFORM]
        7       │- + cpython-3.12.8-[PLATFORM] (python3.12)
              5 │+Installed Python 3.12.6 in [TIME]
              6 │+ + cpython-3.12.6-[PLATFORM] (python3.12)
              7 │+error: Failed to install cpython-3.12.8-[PLATFORM]
              8 │+  Caused by: Failed to download https://github.com/astral-sh/python-build-standalone/releases/download/20250115/cpython-3.12.8%2B20250115-x86_64-pc-windows-msvc-install_only_stripped.tar.gz
              9 │+  Caused by: HTTP status server error (500 Internal Server Error) for url (https://github.com/astral-sh/python-build-standalone/releases/download/20250115/cpython-3.12.8%2B20250115-x86_64-pc-windows-msvc-install_only_stripped.tar.gz)
    ────────────┴──────────────────────────────────────────────────────────────────
    Stopped on the first failure. Run `cargo insta test` to run all snapshots.
    test python_install::python_install_preview ... FAILED

Adding an empty commit to force a rerun fixed this temporary issue, though maybe it might be good to add retry logic for this?

Anyway, all tests passing now! 🎉

Screenshot 2025-06-06 at 5 57 43 AM

@zanieb zanieb added the needs-decision Undecided if this should be done label Jun 6, 2025
@zanieb
Copy link
Member

zanieb commented Jun 6, 2025

Thanks for the pull request.

As a brief note, we do not have consensus on a design for this and are very unlikely to accept a pull request without reaching that consensus first. We may be able to use this proposal to help drive consensus forward, but I want to set the right expectations here.

@msabramo
Copy link
Author

msabramo commented Jun 6, 2025

Thanks for the pull request.

As a brief note, we do not have consensus on a design for this and are very unlikely to accept a pull request without reaching that consensus first. We may be able to use this proposal to help drive consensus forward, but I want to set the right expectations here.

@zanieb

Yeah understood, I know this is kind of controversial. I was just composing a comment on the issue with a proposal about how to solve some of the concerns. That proposal is not implemented in this PR, but if by discussion we come to some solution that people are happy with, then I could add it to this PR.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

needs-decision Undecided if this should be done

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Expand environment variables in user-provided index URLs

2 participants