mirror of https://github.com/astral-sh/uv
Propagate credentials for `<index>/simple` to `<index>/...` endpoints (#11074)
Closes https://github.com/astral-sh/uv/issues/11017 Closes https://github.com/astral-sh/uv/issues/8565 Sort of an minimal implementation of https://github.com/astral-sh/uv/issues/4583
This commit is contained in:
parent
d281f49103
commit
1dfa650ab4
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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};
|
||||
|
|
@ -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};
|
||||
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
use std::collections::BTreeSet;
|
||||
use std::fmt::Write;
|
||||
use std::sync::Arc;
|
||||
|
||||
use itertools::Itertools;
|
||||
use owo_colors::OwoColorize;
|
||||
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
use std::collections::BTreeSet;
|
||||
use std::fmt::Write;
|
||||
use std::sync::Arc;
|
||||
|
||||
use anyhow::Result;
|
||||
use owo_colors::OwoColorize;
|
||||
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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::{
|
||||
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -8347,15 +8347,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(())
|
||||
|
|
|
|||
Loading…
Reference in New Issue