Skip to content

Commit e7ae0f5

Browse files
authored
Respect allow insecure host in publish (#8440)
1 parent 614013e commit e7ae0f5

File tree

8 files changed

+38
-30
lines changed

8 files changed

+38
-30
lines changed

crates/uv-client/src/base_client.rs

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -350,16 +350,6 @@ enum Security {
350350
}
351351

352352
impl BaseClient {
353-
/// The underlying [`ClientWithMiddleware`] for secure requests.
354-
pub fn client(&self) -> ClientWithMiddleware {
355-
self.client.clone()
356-
}
357-
358-
/// The underlying [`Client`] without middleware.
359-
pub fn raw_client(&self) -> Client {
360-
self.raw_client.clone()
361-
}
362-
363353
/// Selects the appropriate client based on the host's trustworthiness.
364354
pub fn for_host(&self, url: &Url) -> &ClientWithMiddleware {
365355
if self

crates/uv-client/tests/it/user_agent_version.rs

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,9 @@ use hyper::service::service_fn;
88
use hyper::{Request, Response};
99
use hyper_util::rt::TokioIo;
1010
use insta::{assert_json_snapshot, assert_snapshot, with_settings};
11+
use std::str::FromStr;
1112
use tokio::net::TcpListener;
12-
13+
use url::Url;
1314
use uv_cache::Cache;
1415
use uv_client::LineHaul;
1516
use uv_client::RegistryClientBuilder;
@@ -53,11 +54,12 @@ async fn test_user_agent_has_version() -> Result<()> {
5354
let client = RegistryClientBuilder::new(cache).build();
5455

5556
// Send request to our dummy server
57+
let url = Url::from_str(&format!("http://{addr}"))?;
5658
let res = client
5759
.cached_client()
5860
.uncached()
59-
.client()
60-
.get(format!("http://{addr}"))
61+
.for_host(&url)
62+
.get(url)
6163
.send()
6264
.await?;
6365

@@ -149,11 +151,12 @@ async fn test_user_agent_has_linehaul() -> Result<()> {
149151
let client = builder.build();
150152

151153
// Send request to our dummy server
154+
let url = Url::from_str(&format!("http://{addr}"))?;
152155
let res = client
153156
.cached_client()
154157
.uncached()
155-
.client()
156-
.get(format!("http://{addr}"))
158+
.for_host(&url)
159+
.get(url)
157160
.send()
158161
.await?;
159162

crates/uv-publish/src/lib.rs

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ use itertools::Itertools;
1010
use reqwest::header::AUTHORIZATION;
1111
use reqwest::multipart::Part;
1212
use reqwest::{Body, Response, StatusCode};
13-
use reqwest_middleware::{ClientWithMiddleware, RequestBuilder};
13+
use reqwest_middleware::RequestBuilder;
1414
use reqwest_retry::{Retryable, RetryableStrategy};
1515
use rustc_hash::FxHashSet;
1616
use serde::Deserialize;
@@ -24,7 +24,7 @@ use tokio::io::AsyncReadExt;
2424
use tokio_util::io::ReaderStream;
2525
use tracing::{debug, enabled, trace, Level};
2626
use url::Url;
27-
use uv_client::UvRetryableStrategy;
27+
use uv_client::{BaseClient, UvRetryableStrategy};
2828
use uv_configuration::{KeyringProviderType, TrustedPublishing};
2929
use uv_distribution_filename::{DistFilename, SourceDistExtension, SourceDistFilename};
3030
use uv_fs::{ProgressReader, Simplified};
@@ -246,7 +246,7 @@ pub async fn check_trusted_publishing(
246246
keyring_provider: KeyringProviderType,
247247
trusted_publishing: TrustedPublishing,
248248
registry: &Url,
249-
client: &ClientWithMiddleware,
249+
client: &BaseClient,
250250
) -> Result<Option<TrustedPublishingToken>, PublishError> {
251251
match trusted_publishing {
252252
TrustedPublishing::Automatic => {
@@ -264,7 +264,7 @@ pub async fn check_trusted_publishing(
264264
// We could check for credentials from the keyring or netrc the auth middleware first, but
265265
// given that we are in GitHub Actions we check for trusted publishing first.
266266
debug!("Running on GitHub Actions without explicit credentials, checking for trusted publishing");
267-
match trusted_publishing::get_token(registry, client).await {
267+
match trusted_publishing::get_token(registry, client.for_host(registry)).await {
268268
Ok(token) => Ok(Some(token)),
269269
Err(err) => {
270270
// TODO(konsti): It would be useful if we could differentiate between actual errors
@@ -283,7 +283,7 @@ pub async fn check_trusted_publishing(
283283
);
284284
}
285285

286-
let token = trusted_publishing::get_token(registry, client).await?;
286+
let token = trusted_publishing::get_token(registry, client.for_host(registry)).await?;
287287
Ok(Some(token))
288288
}
289289
TrustedPublishing::Never => Ok(None),
@@ -300,7 +300,7 @@ pub async fn upload(
300300
raw_filename: &str,
301301
filename: &DistFilename,
302302
registry: &Url,
303-
client: &ClientWithMiddleware,
303+
client: &BaseClient,
304304
retries: u32,
305305
username: Option<&str>,
306306
password: Option<&str>,
@@ -504,7 +504,7 @@ async fn build_request(
504504
raw_filename: &str,
505505
filename: &DistFilename,
506506
registry: &Url,
507-
client: &ClientWithMiddleware,
507+
client: &BaseClient,
508508
username: Option<&str>,
509509
password: Option<&str>,
510510
form_metadata: &[(&'static str, String)],
@@ -543,6 +543,7 @@ async fn build_request(
543543
};
544544

545545
let mut request = client
546+
.for_host(&url)
546547
.post(url)
547548
.multipart(form)
548549
// Ask PyPI for a structured error messages instead of HTML-markup error messages.

crates/uv-publish/src/tests.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ async fn upload_request_source_dist() {
8484
raw_filename,
8585
&filename,
8686
&Url::parse("https://example.org/upload").unwrap(),
87-
&BaseClientBuilder::new().build().client(),
87+
&BaseClientBuilder::new().build(),
8888
Some("ferris"),
8989
Some("F3RR!S"),
9090
&form_metadata,
@@ -229,7 +229,7 @@ async fn upload_request_wheel() {
229229
raw_filename,
230230
&filename,
231231
&Url::parse("https://example.org/upload").unwrap(),
232-
&BaseClientBuilder::new().build().client(),
232+
&BaseClientBuilder::new().build(),
233233
Some("ferris"),
234234
Some("F3RR!S"),
235235
&form_metadata,

crates/uv-python/src/downloads.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -694,7 +694,7 @@ async fn read_url(
694694

695695
Ok((Either::Left(reader), Some(size)))
696696
} else {
697-
let response = client.client().get(url.clone()).send().await?;
697+
let response = client.for_host(url).get(url.clone()).send().await?;
698698

699699
// Ensure the request was successful.
700700
response.error_for_status_ref()?;

crates/uv-requirements-txt/src/lib.rs

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -798,9 +798,11 @@ async fn read_url_to_string(
798798
url: path.as_ref().to_owned(),
799799
})?;
800800

801+
let url = Url::from_str(path_utf8)
802+
.map_err(|err| RequirementsTxtParserError::InvalidUrl(path_utf8.to_string(), err))?;
801803
Ok(client
802-
.client()
803-
.get(path_utf8)
804+
.for_host(&url)
805+
.get(url)
804806
.send()
805807
.await?
806808
.error_for_status()?
@@ -890,6 +892,8 @@ pub enum RequirementsTxtParserError {
890892
},
891893
#[cfg(feature = "http")]
892894
Reqwest(reqwest_middleware::Error),
895+
#[cfg(feature = "http")]
896+
InvalidUrl(String, url::ParseError),
893897
}
894898

895899
impl Display for RequirementsTxtParserError {
@@ -956,6 +960,10 @@ impl Display for RequirementsTxtParserError {
956960
Self::Reqwest(err) => {
957961
write!(f, "Error while accessing remote requirements file {err}")
958962
}
963+
#[cfg(feature = "http")]
964+
Self::InvalidUrl(url, err) => {
965+
write!(f, "Not a valid URL, {err}: `{url}`")
966+
}
959967
}
960968
}
961969
}
@@ -982,6 +990,8 @@ impl std::error::Error for RequirementsTxtParserError {
982990
Self::NonUnicodeUrl { .. } => None,
983991
#[cfg(feature = "http")]
984992
Self::Reqwest(err) => err.source(),
993+
#[cfg(feature = "http")]
994+
Self::InvalidUrl(_, err) => err.source(),
985995
}
986996
}
987997
}
@@ -1114,6 +1124,10 @@ impl Display for RequirementsTxtFileError {
11141124
self.file.user_display(),
11151125
)
11161126
}
1127+
#[cfg(feature = "http")]
1128+
RequirementsTxtParserError::InvalidUrl(url, err) => {
1129+
write!(f, "Not a valid URL, {err}: `{url}`")
1130+
}
11171131
}
11181132
}
11191133
}

crates/uv/src/commands/project/run.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1185,7 +1185,7 @@ impl RunCommand {
11851185
.connectivity(connectivity)
11861186
.native_tls(native_tls)
11871187
.build();
1188-
let response = client.client().get(url.clone()).send().await?;
1188+
let response = client.for_host(&url).get(url.clone()).send().await?;
11891189

11901190
// Stream the response to the file.
11911191
let mut writer = file.as_file();

crates/uv/src/commands/publish.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ pub(crate) async fn publish(
6767
keyring_provider,
6868
trusted_publishing,
6969
&publish_url,
70-
&oidc_client.client(),
70+
&oidc_client,
7171
)
7272
.await?;
7373

@@ -104,7 +104,7 @@ pub(crate) async fn publish(
104104
&raw_filename,
105105
&filename,
106106
&publish_url,
107-
&upload_client.client(),
107+
&upload_client,
108108
DEFAULT_RETRIES,
109109
username.as_deref(),
110110
password.as_deref(),

0 commit comments

Comments
 (0)