Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 8 additions & 5 deletions crates/uv-client/src/base_client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -387,17 +387,20 @@ enum Security {
impl BaseClient {
/// Selects the appropriate client based on the host's trustworthiness.
pub fn for_host(&self, url: &Url) -> &ClientWithMiddleware {
if self
.allow_insecure_host
.iter()
.any(|allow_insecure_host| allow_insecure_host.matches(url))
{
if self.disable_ssl(url) {
&self.dangerous_client
} else {
&self.client
}
}

/// Returns `true` if the host is trusted to use the insecure client.
pub fn disable_ssl(&self, url: &Url) -> bool {
self.allow_insecure_host
.iter()
.any(|allow_insecure_host| allow_insecure_host.matches(url))
}

/// The configured client timeout, in seconds.
pub fn timeout(&self) -> Duration {
self.timeout
Expand Down
5 changes: 5 additions & 0 deletions crates/uv-client/src/registry_client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,11 @@ impl RegistryClient {
self.client.uncached().for_host(url)
}

/// Returns `true` if SSL verification is disabled for the given URL.
pub fn disable_ssl(&self, url: &Url) -> bool {
self.client.uncached().disable_ssl(url)
}

/// Return the [`Connectivity`] mode used by this client.
pub fn connectivity(&self) -> Connectivity {
self.connectivity
Expand Down
18 changes: 15 additions & 3 deletions crates/uv-distribution/src/source/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1430,7 +1430,11 @@ impl<'a, T: BuildContext> SourceDistributionBuilder<'a, T> {
.git()
.fetch(
resource.git,
client.unmanaged.uncached_client(resource.url).clone(),
client
.unmanaged
.uncached_client(resource.git.repository())
.clone(),
client.unmanaged.disable_ssl(resource.git.repository()),
self.build_context.cache().bucket(CacheBucket::Git),
self.reporter
.clone()
Expand Down Expand Up @@ -1530,7 +1534,10 @@ impl<'a, T: BuildContext> SourceDistributionBuilder<'a, T> {
.git()
.github_fast_path(
resource.git,
client.unmanaged.uncached_client(resource.url).clone(),
client
.unmanaged
.uncached_client(resource.git.repository())
.clone(),
)
.await
{
Expand Down Expand Up @@ -1582,7 +1589,11 @@ impl<'a, T: BuildContext> SourceDistributionBuilder<'a, T> {
.git()
.fetch(
resource.git,
client.unmanaged.uncached_client(resource.url).clone(),
client
.unmanaged
.uncached_client(resource.git.repository())
.clone(),
client.unmanaged.disable_ssl(resource.git.repository()),
self.build_context.cache().bucket(CacheBucket::Git),
self.reporter
.clone()
Expand Down Expand Up @@ -1812,6 +1823,7 @@ impl<'a, T: BuildContext> SourceDistributionBuilder<'a, T> {
.fetch(
git,
client.unmanaged.uncached_client(git.repository()).clone(),
client.unmanaged.disable_ssl(git.repository()),
self.build_context.cache().bucket(CacheBucket::Git),
self.reporter
.clone()
Expand Down
40 changes: 32 additions & 8 deletions crates/uv-git/src/git.rs
Original file line number Diff line number Diff line change
Expand Up @@ -303,14 +303,15 @@ impl GitRemote {
reference: &GitReference,
locked_rev: Option<GitOid>,
client: &ClientWithMiddleware,
disable_ssl: bool,
) -> Result<(GitDatabase, GitOid)> {
let reference = locked_rev
.map(ReferenceOrOid::Oid)
.unwrap_or(ReferenceOrOid::Reference(reference));
let enable_lfs_fetch = env::var(EnvVars::UV_GIT_LFS).is_ok();

if let Some(mut db) = db {
fetch(&mut db.repo, &self.url, reference, client)
fetch(&mut db.repo, &self.url, reference, client, disable_ssl)
.with_context(|| format!("failed to fetch into: {}", into.user_display()))?;

let resolved_commit_hash = match locked_rev {
Expand All @@ -320,7 +321,7 @@ impl GitRemote {

if let Some(rev) = resolved_commit_hash {
if enable_lfs_fetch {
fetch_lfs(&mut db.repo, &self.url, &rev)
fetch_lfs(&mut db.repo, &self.url, &rev, disable_ssl)
.with_context(|| format!("failed to fetch LFS objects at {rev}"))?;
}
return Ok((db, rev));
Expand All @@ -338,14 +339,14 @@ impl GitRemote {

fs_err::create_dir_all(into)?;
let mut repo = GitRepository::init(into)?;
fetch(&mut repo, &self.url, reference, client)
fetch(&mut repo, &self.url, reference, client, disable_ssl)
.with_context(|| format!("failed to clone into: {}", into.user_display()))?;
let rev = match locked_rev {
Some(rev) => rev,
None => reference.resolve(&repo)?,
};
if enable_lfs_fetch {
fetch_lfs(&mut repo, &self.url, &rev)
fetch_lfs(&mut repo, &self.url, &rev, disable_ssl)
.with_context(|| format!("failed to fetch LFS objects at {rev}"))?;
}

Expand Down Expand Up @@ -502,6 +503,7 @@ fn fetch(
remote_url: &Url,
reference: ReferenceOrOid<'_>,
client: &ClientWithMiddleware,
disable_ssl: bool,
) -> Result<()> {
let oid_to_fetch = match github_fast_path(repo, remote_url, reference, client) {
Ok(FastPathRev::UpToDate) => return Ok(()),
Expand Down Expand Up @@ -577,14 +579,21 @@ fn fetch(

debug!("Performing a Git fetch for: {remote_url}");
let result = match refspec_strategy {
RefspecStrategy::All => fetch_with_cli(repo, remote_url, refspecs.as_slice(), tags),
RefspecStrategy::All => {
fetch_with_cli(repo, remote_url, refspecs.as_slice(), tags, disable_ssl)
}
RefspecStrategy::First => {
// Try each refspec
let mut errors = refspecs
.iter()
.map_while(|refspec| {
let fetch_result =
fetch_with_cli(repo, remote_url, std::slice::from_ref(refspec), tags);
let fetch_result = fetch_with_cli(
repo,
remote_url,
std::slice::from_ref(refspec),
tags,
disable_ssl,
);

// Stop after the first success and log failures
match fetch_result {
Expand Down Expand Up @@ -629,12 +638,17 @@ fn fetch_with_cli(
url: &Url,
refspecs: &[String],
tags: bool,
disable_ssl: bool,
) -> Result<()> {
let mut cmd = ProcessBuilder::new(GIT.as_ref()?);
cmd.arg("fetch");
if tags {
cmd.arg("--tags");
}
if disable_ssl {
debug!("Disabling SSL verification for Git fetch");
cmd.env(EnvVars::GIT_SSL_NO_VERIFY, "true");
}
cmd.arg("--force") // handle force pushes
.arg("--update-head-ok") // see discussion in #2078
.arg(url.as_str())
Expand Down Expand Up @@ -674,7 +688,12 @@ static GIT_LFS: LazyLock<Result<ProcessBuilder>> = LazyLock::new(|| {
});

/// Attempts to use `git-lfs` CLI to fetch required LFS objects for a given revision.
fn fetch_lfs(repo: &mut GitRepository, url: &Url, revision: &GitOid) -> Result<()> {
fn fetch_lfs(
repo: &mut GitRepository,
url: &Url,
revision: &GitOid,
disable_ssl: bool,
) -> Result<()> {
let mut cmd = if let Ok(lfs) = GIT_LFS.as_ref() {
debug!("Fetching Git LFS objects");
lfs.clone()
Expand All @@ -684,6 +703,11 @@ fn fetch_lfs(repo: &mut GitRepository, url: &Url, revision: &GitOid) -> Result<(
return Ok(());
};

if disable_ssl {
debug!("Disabling SSL verification for Git LFS");
cmd.env(EnvVars::GIT_SSL_NO_VERIFY, "true");
}

cmd.arg("fetch")
.arg(url.as_str())
.arg(revision.as_str())
Expand Down
9 changes: 9 additions & 0 deletions crates/uv-git/src/resolver.rs
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@ impl GitResolver {
&self,
url: &GitUrl,
client: ClientWithMiddleware,
disable_ssl: bool,
cache: PathBuf,
reporter: Option<Arc<dyn Reporter>>,
) -> Result<Fetch, GitResolverError> {
Expand Down Expand Up @@ -139,6 +140,14 @@ impl GitResolver {
} else {
GitSource::new(url.as_ref().clone(), client, cache)
};

// If necessary, disable SSL.
let source = if disable_ssl {
source.dangerous()
} else {
source
};

let fetch = tokio::task::spawn_blocking(move || source.fetch())
.await?
.map_err(GitResolverError::Git)?;
Expand Down
13 changes: 13 additions & 0 deletions crates/uv-git/src/source.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ pub struct GitSource {
git: GitUrl,
/// The HTTP client to use for fetching.
client: ClientWithMiddleware,
/// Whether to disable SSL verification.
disable_ssl: bool,
/// The path to the Git source database.
cache: PathBuf,
/// The reporter to use for this source.
Expand All @@ -37,12 +39,22 @@ impl GitSource {
) -> Self {
Self {
git,
disable_ssl: false,
client: client.into(),
cache: cache.into(),
reporter: None,
}
}

/// Disable SSL verification for this [`GitSource`].
#[must_use]
pub fn dangerous(self) -> Self {
Self {
disable_ssl: true,
..self
}
}

/// Set the [`Reporter`] to use for the [`GitSource`].
#[must_use]
pub fn with_reporter(self, reporter: Arc<dyn Reporter>) -> Self {
Expand Down Expand Up @@ -96,6 +108,7 @@ impl GitSource {
&self.git.reference,
locked_rev.map(GitOid::from),
&self.client,
self.disable_ssl,
)?;

(db, actual_rev, task)
Expand Down
4 changes: 4 additions & 0 deletions crates/uv-static/src/env_vars.rs
Original file line number Diff line number Diff line change
Expand Up @@ -449,6 +449,10 @@ impl EnvVars {
#[attr_hidden]
pub const GIT_ALTERNATE_OBJECT_DIRECTORIES: &'static str = "GIT_ALTERNATE_OBJECT_DIRECTORIES";

/// Disables SSL verification for git operations.
#[attr_hidden]
pub const GIT_SSL_NO_VERIFY: &'static str = "GIT_SSL_NO_VERIFY";

/// Used in tests for better git isolation.
///
/// For example, we run some tests in ~/.local/share/uv/tests.
Expand Down
Loading