Make cache control lookups robust to username (#16088)

## Summary

We serialize the index to the lockfile without the username, so if we
compare based on `==` and the user _includes_ the username in their
`pyproject.toml`, the check will always fail.

Closes https://github.com/astral-sh/uv/issues/16076.
This commit is contained in:
Charlie Marsh 2025-10-01 16:57:50 -04:00 committed by GitHub
parent d483b02e61
commit c2100d11f3
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 15 additions and 8 deletions

View File

@ -14,7 +14,7 @@ pub use middleware::AuthMiddleware;
pub use pyx::{ pub use pyx::{
DEFAULT_TOLERANCE_SECS, PyxJwt, PyxOAuthTokens, PyxTokenStore, PyxTokens, TokenStoreError, DEFAULT_TOLERANCE_SECS, PyxJwt, PyxOAuthTokens, PyxTokenStore, PyxTokens, TokenStoreError,
}; };
pub use realm::Realm; pub use realm::{Realm, RealmRef};
pub use service::{Service, ServiceParseError}; pub use service::{Service, ServiceParseError};
pub use store::{AuthBackend, AuthScheme, TextCredentialStore, TomlCredentialError}; pub use store::{AuthBackend, AuthScheme, TextCredentialStore, TomlCredentialError};

View File

@ -75,7 +75,7 @@ impl Hash for Realm {
/// A reference to a [`Realm`] that can be used for zero-allocation comparisons. /// A reference to a [`Realm`] that can be used for zero-allocation comparisons.
#[derive(Debug, Copy, Clone)] #[derive(Debug, Copy, Clone)]
pub(crate) struct RealmRef<'a> { pub struct RealmRef<'a> {
scheme: &'a str, scheme: &'a str,
host: Option<&'a str>, host: Option<&'a str>,
port: Option<u16>, port: Option<u16>,

View File

@ -10,7 +10,8 @@ use rustc_hash::{FxHashMap, FxHashSet};
use thiserror::Error; use thiserror::Error;
use tracing::trace; use tracing::trace;
use url::{ParseError, Url}; use url::{ParseError, Url};
use uv_auth::RealmRef;
use uv_cache_key::CanonicalUrl;
use uv_pep508::{Scheme, VerbatimUrl, VerbatimUrlError, split_scheme}; use uv_pep508::{Scheme, VerbatimUrl, VerbatimUrlError, split_scheme};
use uv_redacted::DisplaySafeUrl; use uv_redacted::DisplaySafeUrl;
use uv_warnings::warn_user; use uv_warnings::warn_user;
@ -292,6 +293,12 @@ impl IndexLocations {
} }
} }
/// Returns `true` if two [`IndexUrl`]s refer to the same index.
fn is_same_index(a: &IndexUrl, b: &IndexUrl) -> bool {
RealmRef::from(&**b.url()) == RealmRef::from(&**a.url())
&& CanonicalUrl::new(a.url()) == CanonicalUrl::new(b.url())
}
impl<'a> IndexLocations { impl<'a> IndexLocations {
/// Return the default [`Index`] entry. /// Return the default [`Index`] entry.
/// ///
@ -456,7 +463,7 @@ impl<'a> IndexLocations {
/// Return the Simple API cache control header for an [`IndexUrl`], if configured. /// Return the Simple API cache control header for an [`IndexUrl`], if configured.
pub fn simple_api_cache_control_for(&self, url: &IndexUrl) -> Option<&str> { pub fn simple_api_cache_control_for(&self, url: &IndexUrl) -> Option<&str> {
for index in &self.indexes { for index in &self.indexes {
if index.url() == url { if is_same_index(index.url(), url) {
return index.simple_api_cache_control(); return index.simple_api_cache_control();
} }
} }
@ -466,7 +473,7 @@ impl<'a> IndexLocations {
/// Return the artifact cache control header for an [`IndexUrl`], if configured. /// Return the artifact cache control header for an [`IndexUrl`], if configured.
pub fn artifact_cache_control_for(&self, url: &IndexUrl) -> Option<&str> { pub fn artifact_cache_control_for(&self, url: &IndexUrl) -> Option<&str> {
for index in &self.indexes { for index in &self.indexes {
if index.url() == url { if is_same_index(index.url(), url) {
return index.artifact_cache_control(); return index.artifact_cache_control();
} }
} }
@ -599,7 +606,7 @@ impl<'a> IndexUrls {
/// Return the [`IndexStatusCodeStrategy`] for an [`IndexUrl`]. /// Return the [`IndexStatusCodeStrategy`] for an [`IndexUrl`].
pub fn status_code_strategy_for(&self, url: &IndexUrl) -> IndexStatusCodeStrategy { pub fn status_code_strategy_for(&self, url: &IndexUrl) -> IndexStatusCodeStrategy {
for index in &self.indexes { for index in &self.indexes {
if index.url() == url { if is_same_index(index.url(), url) {
return index.status_code_strategy(); return index.status_code_strategy();
} }
} }
@ -609,7 +616,7 @@ impl<'a> IndexUrls {
/// Return the Simple API cache control header for an [`IndexUrl`], if configured. /// Return the Simple API cache control header for an [`IndexUrl`], if configured.
pub fn simple_api_cache_control_for(&self, url: &IndexUrl) -> Option<&str> { pub fn simple_api_cache_control_for(&self, url: &IndexUrl) -> Option<&str> {
for index in &self.indexes { for index in &self.indexes {
if index.url() == url { if is_same_index(index.url(), url) {
return index.simple_api_cache_control(); return index.simple_api_cache_control();
} }
} }
@ -619,7 +626,7 @@ impl<'a> IndexUrls {
/// Return the artifact cache control header for an [`IndexUrl`], if configured. /// Return the artifact cache control header for an [`IndexUrl`], if configured.
pub fn artifact_cache_control_for(&self, url: &IndexUrl) -> Option<&str> { pub fn artifact_cache_control_for(&self, url: &IndexUrl) -> Option<&str> {
for index in &self.indexes { for index in &self.indexes {
if index.url() == url { if is_same_index(index.url(), url) {
return index.artifact_cache_control(); return index.artifact_cache_control();
} }
} }