Skip to content

Commit

Permalink
Propagate credentials for <index>/simple to <index>/... endpoints
Browse files Browse the repository at this point in the history
  • Loading branch information
zanieb committed Jan 29, 2025
1 parent ae76a4b commit dfe65ed
Show file tree
Hide file tree
Showing 12 changed files with 103 additions and 24 deletions.
4 changes: 2 additions & 2 deletions crates/uv-auth/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ pub fn store_credentials_from_url(url: &Url) -> bool {
/// Populate the global authentication store with credentials on a URL, if there are any.
///
/// Returns `true` if the store was updated.
pub fn store_credentials(url: &Url, credentials: Credentials) {
pub fn store_credentials(url: &Url, credentials: Arc<Credentials>) {
trace!("Caching credentials for {url}");
CREDENTIALS_CACHE.insert(url, Arc::new(credentials));
CREDENTIALS_CACHE.insert(url, credentials);
}
18 changes: 17 additions & 1 deletion crates/uv-distribution-types/src/index.rs
Original file line number Diff line number Diff line change
Expand Up @@ -150,11 +150,27 @@ impl Index {
self.url
}

/// Return the raw [`URL`] of the index.
/// Return the raw [`Url`] of the index.
pub fn raw_url(&self) -> &Url {
self.url.url()
}

/// Return the root [`Url`] of the index, if applicable.
///
/// For indexes with a `/simple` endpoint, this is simply the URL with the final segment
/// removed. This is useful, e.g., for credential propagation to other endpoints on the index.
pub fn root_url(&self) -> Option<Url> {
let segments = self.raw_url().path_segments()?;
let last = segments.last()?;
if !last.eq_ignore_ascii_case("simple") {
return None;
}

let mut url = self.raw_url().clone();
url.path_segments_mut().ok()?.pop();
Some(url)
}

/// Retrieve the credentials for the index, either from the environment, or from the URL itself.
pub fn credentials(&self) -> Option<Credentials> {
// If the index is named, and credentials are provided via the environment, prefer those.
Expand Down
8 changes: 6 additions & 2 deletions crates/uv/src/commands/build_frontend.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use std::fmt::Write as _;
use std::io::Write as _;
use std::path::{Path, PathBuf};
use std::str::FromStr;
use std::sync::Arc;
use std::{fmt, io};

use anyhow::{Context, Result};
Expand All @@ -16,7 +17,6 @@ use crate::commands::reporters::PythonDownloadReporter;
use crate::commands::ExitStatus;
use crate::printer::Printer;
use crate::settings::{ResolverSettings, ResolverSettingsRef};
use uv_auth::store_credentials;
use uv_build_backend::check_direct_build;
use uv_cache::{Cache, CacheBucket};
use uv_client::{BaseClientBuilder, Connectivity, FlatIndexClient, RegistryClientBuilder};
Expand Down Expand Up @@ -496,7 +496,11 @@ async fn build_package(
// Add all authenticated sources to the cache.
for index in index_locations.allowed_indexes() {
if let Some(credentials) = index.credentials() {
store_credentials(index.raw_url(), credentials);
let credentials = Arc::new(credentials);
uv_auth::store_credentials(index.raw_url(), credentials.clone());
if let Some(root_url) = index.root_url() {
uv_auth::store_credentials(&root_url, credentials.clone());
}
}
}

Expand Down
7 changes: 6 additions & 1 deletion crates/uv/src/commands/pip/compile.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use std::collections::BTreeSet;
use std::env;
use std::path::Path;
use std::sync::Arc;

use anyhow::{anyhow, Result};
use itertools::Itertools;
Expand Down Expand Up @@ -292,7 +293,11 @@ pub(crate) async fn pip_compile(
// Add all authenticated sources to the cache.
for index in index_locations.allowed_indexes() {
if let Some(credentials) = index.credentials() {
uv_auth::store_credentials(index.raw_url(), credentials);
let credentials = Arc::new(credentials);
uv_auth::store_credentials(index.raw_url(), credentials.clone());
if let Some(root_url) = index.root_url() {
uv_auth::store_credentials(&root_url, credentials.clone());
}
}
}

Expand Down
7 changes: 6 additions & 1 deletion crates/uv/src/commands/pip/install.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use std::collections::BTreeSet;
use std::fmt::Write;
use std::sync::Arc;

use itertools::Itertools;
use owo_colors::OwoColorize;
Expand Down Expand Up @@ -311,7 +312,11 @@ pub(crate) async fn pip_install(
// Add all authenticated sources to the cache.
for index in index_locations.allowed_indexes() {
if let Some(credentials) = index.credentials() {
uv_auth::store_credentials(index.raw_url(), credentials);
let credentials = Arc::new(credentials);
uv_auth::store_credentials(index.raw_url(), credentials.clone());
if let Some(root_url) = index.root_url() {
uv_auth::store_credentials(&root_url, credentials.clone());
}
}
}

Expand Down
7 changes: 6 additions & 1 deletion crates/uv/src/commands/pip/sync.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use std::collections::BTreeSet;
use std::fmt::Write;
use std::sync::Arc;

use anyhow::Result;
use owo_colors::OwoColorize;
Expand Down Expand Up @@ -251,7 +252,11 @@ pub(crate) async fn pip_sync(
// Add all authenticated sources to the cache.
for index in index_locations.allowed_indexes() {
if let Some(credentials) = index.credentials() {
uv_auth::store_credentials(index.raw_url(), credentials);
let credentials = Arc::new(credentials);
uv_auth::store_credentials(index.raw_url(), credentials.clone());
if let Some(root_url) = index.root_url() {
uv_auth::store_credentials(&root_url, credentials.clone());
}
}
}

Expand Down
6 changes: 5 additions & 1 deletion crates/uv/src/commands/project/add.rs
Original file line number Diff line number Diff line change
Expand Up @@ -286,7 +286,11 @@ pub(crate) async fn add(
// Add all authenticated sources to the cache.
for index in settings.index_locations.allowed_indexes() {
if let Some(credentials) = index.credentials() {
uv_auth::store_credentials(index.raw_url(), credentials);
let credentials = Arc::new(credentials);
uv_auth::store_credentials(index.raw_url(), credentials.clone());
if let Some(root_url) = index.root_url() {
uv_auth::store_credentials(&root_url, credentials.clone());
}
}
}

Expand Down
12 changes: 10 additions & 2 deletions crates/uv/src/commands/project/lock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -466,13 +466,21 @@ async fn do_lock(
// Add all authenticated sources to the cache.
for index in index_locations.allowed_indexes() {
if let Some(credentials) = index.credentials() {
uv_auth::store_credentials(index.raw_url(), credentials);
let credentials = Arc::new(credentials);
uv_auth::store_credentials(index.raw_url(), credentials.clone());
if let Some(root_url) = index.root_url() {
uv_auth::store_credentials(&root_url, credentials.clone());
}
}
}

for index in target.indexes() {
if let Some(credentials) = index.credentials() {
uv_auth::store_credentials(index.raw_url(), credentials);
let credentials = Arc::new(credentials);
uv_auth::store_credentials(index.raw_url(), credentials.clone());
if let Some(root_url) = index.root_url() {
uv_auth::store_credentials(&root_url, credentials.clone());
}
}
}

Expand Down
24 changes: 20 additions & 4 deletions crates/uv/src/commands/project/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1078,7 +1078,11 @@ pub(crate) async fn resolve_names(
// Add all authenticated sources to the cache.
for index in index_locations.allowed_indexes() {
if let Some(credentials) = index.credentials() {
uv_auth::store_credentials(index.raw_url(), credentials);
let credentials = Arc::new(credentials);
uv_auth::store_credentials(index.raw_url(), credentials.clone());
if let Some(root_url) = index.root_url() {
uv_auth::store_credentials(&root_url, credentials.clone());
}
}
}

Expand Down Expand Up @@ -1228,7 +1232,11 @@ pub(crate) async fn resolve_environment(
// Add all authenticated sources to the cache.
for index in index_locations.allowed_indexes() {
if let Some(credentials) = index.credentials() {
uv_auth::store_credentials(index.raw_url(), credentials);
let credentials = Arc::new(credentials);
uv_auth::store_credentials(index.raw_url(), credentials.clone());
if let Some(root_url) = index.root_url() {
uv_auth::store_credentials(&root_url, credentials.clone());
}
}
}

Expand Down Expand Up @@ -1395,7 +1403,11 @@ pub(crate) async fn sync_environment(
// Add all authenticated sources to the cache.
for index in index_locations.allowed_indexes() {
if let Some(credentials) = index.credentials() {
uv_auth::store_credentials(index.raw_url(), credentials);
let credentials = Arc::new(credentials);
uv_auth::store_credentials(index.raw_url(), credentials.clone());
if let Some(root_url) = index.root_url() {
uv_auth::store_credentials(&root_url, credentials.clone());
}
}
}

Expand Down Expand Up @@ -1590,7 +1602,11 @@ pub(crate) async fn update_environment(
// Add all authenticated sources to the cache.
for index in index_locations.allowed_indexes() {
if let Some(credentials) = index.credentials() {
uv_auth::store_credentials(index.raw_url(), credentials);
let credentials = Arc::new(credentials);
uv_auth::store_credentials(index.raw_url(), credentials.clone());
if let Some(root_url) = index.root_url() {
uv_auth::store_credentials(&root_url, credentials.clone());
}
}
}

Expand Down
14 changes: 11 additions & 3 deletions crates/uv/src/commands/project/sync.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
use std::path::Path;
use std::sync::Arc;

use anyhow::{Context, Result};
use itertools::Itertools;

use uv_auth::store_credentials;
use uv_cache::Cache;
use uv_client::{Connectivity, FlatIndexClient, RegistryClientBuilder};
use uv_configuration::{
Expand Down Expand Up @@ -353,7 +353,11 @@ pub(super) async fn do_sync(
// Add all authenticated sources to the cache.
for index in index_locations.allowed_indexes() {
if let Some(credentials) = index.credentials() {
store_credentials(index.raw_url(), credentials);
let credentials = Arc::new(credentials);
uv_auth::store_credentials(index.raw_url(), credentials.clone());
if let Some(root_url) = index.root_url() {
uv_auth::store_credentials(&root_url, credentials.clone());
}
}
}

Expand Down Expand Up @@ -520,7 +524,11 @@ fn store_credentials_from_target(target: InstallTarget<'_>) {
// Iterate over any idnexes in the target.
for index in target.indexes() {
if let Some(credentials) = index.credentials() {
store_credentials(index.raw_url(), credentials);
let credentials = Arc::new(credentials);
uv_auth::store_credentials(index.raw_url(), credentials.clone());
if let Some(root_url) = index.root_url() {
uv_auth::store_credentials(&root_url, credentials.clone());
}
}
}

Expand Down
13 changes: 11 additions & 2 deletions crates/uv/src/commands/venv.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use std::fmt::Write;
use std::path::{Path, PathBuf};
use std::str::FromStr;
use std::sync::Arc;
use std::vec;

use anstream::eprint;
Expand Down Expand Up @@ -233,7 +234,11 @@ async fn venv_impl(
// Add all authenticated sources to the cache.
for index in index_locations.allowed_indexes() {
if let Some(credentials) = index.credentials() {
uv_auth::store_credentials(index.raw_url(), credentials);
let credentials = Arc::new(credentials);
uv_auth::store_credentials(index.raw_url(), credentials.clone());
if let Some(root_url) = index.root_url() {
uv_auth::store_credentials(&root_url, credentials.clone());
}
}
}

Expand Down Expand Up @@ -280,7 +285,11 @@ async fn venv_impl(
// Add all authenticated sources to the cache.
for index in index_locations.allowed_indexes() {
if let Some(credentials) = index.credentials() {
uv_auth::store_credentials(index.raw_url(), credentials);
let credentials = Arc::new(credentials);
uv_auth::store_credentials(index.raw_url(), credentials.clone());
if let Some(root_url) = index.root_url() {
uv_auth::store_credentials(&root_url, credentials.clone());
}
}
}

Expand Down
7 changes: 3 additions & 4 deletions crates/uv/tests/it/lock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8341,15 +8341,14 @@ fn lock_multiple_indexes_same_realm_different_credentials() -> Result<()> {
.env(EnvVars::index_password("INTERNAL_PROXY_HERON"), "heron")
.env(EnvVars::index_username("INTERNAL_PROXY_EAGLE"), "public")
.env(EnvVars::index_password("INTERNAL_PROXY_EAGLE"), "eagle"), @r###"
success: false
exit_code: 2
success: true
exit_code: 0
----- stdout -----

----- stderr -----
warning: Missing version constraint (e.g., a lower bound) for `iniconfig`
warning: Missing version constraint (e.g., a lower bound) for `anyio`
error: Failed to fetch: `https://pypi-proxy.fly.dev/basic-auth-heron/files/packages/ef/a6/62565a6e1cf69e10f5727360368e451d4b7f58beeac6173dc9db836a5b46/iniconfig-2.0.0-py3-none-any.whl.metadata`
Caused by: HTTP status client error (401 Unauthorized) for url (https://pypi-proxy.fly.dev/basic-auth-heron/files/packages/ef/a6/62565a6e1cf69e10f5727360368e451d4b7f58beeac6173dc9db836a5b46/iniconfig-2.0.0-py3-none-any.whl.metadata)
Resolved 5 packages in [TIME]
"###);

Ok(())
Expand Down

0 comments on commit dfe65ed

Please sign in to comment.