mirror of https://github.com/astral-sh/uv
Disable SSL in Git commands for `--allow-insecure-host` (#11210)
## Summary Closes https://github.com/astral-sh/uv/issues/11176. ## Test Plan - Created a self-signed certificate. - Ran `openssl s_server -cert cert.pem -key key.pem -WWW -port 8443`. - Verified that `cargo run pip install git+https://localhost:8443/repo.git` failed with: ``` error: Git operation failed Caused by: failed to fetch into: /Users/crmarsh/.cache/uv/git-v0/db/0773914b3ec4a56e Caused by: process didn't exit successfully: `/usr/bin/git fetch --force --update-head-ok 'https://localhost:8443/repo.git' '+HEAD:refs/remotes/origin/HEAD'` (exit status: 128) --- stderr fatal: unable to access 'https://localhost:8443/repo.git/': SSL certificate problem: self signed certificate ``` - Verified that `cargo run pip install git+https://localhost:8443/repo.git --allow-insecure-host https://localhost:8443` continued further.
This commit is contained in:
parent
d9907f6fda
commit
748582ee6f
|
|
@ -387,17 +387,20 @@ enum Security {
|
||||||
impl BaseClient {
|
impl BaseClient {
|
||||||
/// Selects the appropriate client based on the host's trustworthiness.
|
/// Selects the appropriate client based on the host's trustworthiness.
|
||||||
pub fn for_host(&self, url: &Url) -> &ClientWithMiddleware {
|
pub fn for_host(&self, url: &Url) -> &ClientWithMiddleware {
|
||||||
if self
|
if self.disable_ssl(url) {
|
||||||
.allow_insecure_host
|
|
||||||
.iter()
|
|
||||||
.any(|allow_insecure_host| allow_insecure_host.matches(url))
|
|
||||||
{
|
|
||||||
&self.dangerous_client
|
&self.dangerous_client
|
||||||
} else {
|
} else {
|
||||||
&self.client
|
&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.
|
/// The configured client timeout, in seconds.
|
||||||
pub fn timeout(&self) -> Duration {
|
pub fn timeout(&self) -> Duration {
|
||||||
self.timeout
|
self.timeout
|
||||||
|
|
|
||||||
|
|
@ -215,6 +215,11 @@ impl RegistryClient {
|
||||||
self.client.uncached().for_host(url)
|
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.
|
/// Return the [`Connectivity`] mode used by this client.
|
||||||
pub fn connectivity(&self) -> Connectivity {
|
pub fn connectivity(&self) -> Connectivity {
|
||||||
self.connectivity
|
self.connectivity
|
||||||
|
|
|
||||||
|
|
@ -1430,7 +1430,11 @@ impl<'a, T: BuildContext> SourceDistributionBuilder<'a, T> {
|
||||||
.git()
|
.git()
|
||||||
.fetch(
|
.fetch(
|
||||||
resource.git,
|
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.build_context.cache().bucket(CacheBucket::Git),
|
||||||
self.reporter
|
self.reporter
|
||||||
.clone()
|
.clone()
|
||||||
|
|
@ -1530,7 +1534,10 @@ impl<'a, T: BuildContext> SourceDistributionBuilder<'a, T> {
|
||||||
.git()
|
.git()
|
||||||
.github_fast_path(
|
.github_fast_path(
|
||||||
resource.git,
|
resource.git,
|
||||||
client.unmanaged.uncached_client(resource.url).clone(),
|
client
|
||||||
|
.unmanaged
|
||||||
|
.uncached_client(resource.git.repository())
|
||||||
|
.clone(),
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
{
|
{
|
||||||
|
|
@ -1582,7 +1589,11 @@ impl<'a, T: BuildContext> SourceDistributionBuilder<'a, T> {
|
||||||
.git()
|
.git()
|
||||||
.fetch(
|
.fetch(
|
||||||
resource.git,
|
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.build_context.cache().bucket(CacheBucket::Git),
|
||||||
self.reporter
|
self.reporter
|
||||||
.clone()
|
.clone()
|
||||||
|
|
@ -1812,6 +1823,7 @@ impl<'a, T: BuildContext> SourceDistributionBuilder<'a, T> {
|
||||||
.fetch(
|
.fetch(
|
||||||
git,
|
git,
|
||||||
client.unmanaged.uncached_client(git.repository()).clone(),
|
client.unmanaged.uncached_client(git.repository()).clone(),
|
||||||
|
client.unmanaged.disable_ssl(git.repository()),
|
||||||
self.build_context.cache().bucket(CacheBucket::Git),
|
self.build_context.cache().bucket(CacheBucket::Git),
|
||||||
self.reporter
|
self.reporter
|
||||||
.clone()
|
.clone()
|
||||||
|
|
|
||||||
|
|
@ -303,6 +303,7 @@ impl GitRemote {
|
||||||
reference: &GitReference,
|
reference: &GitReference,
|
||||||
locked_rev: Option<GitOid>,
|
locked_rev: Option<GitOid>,
|
||||||
client: &ClientWithMiddleware,
|
client: &ClientWithMiddleware,
|
||||||
|
disable_ssl: bool,
|
||||||
) -> Result<(GitDatabase, GitOid)> {
|
) -> Result<(GitDatabase, GitOid)> {
|
||||||
let reference = locked_rev
|
let reference = locked_rev
|
||||||
.map(ReferenceOrOid::Oid)
|
.map(ReferenceOrOid::Oid)
|
||||||
|
|
@ -310,7 +311,7 @@ impl GitRemote {
|
||||||
let enable_lfs_fetch = env::var(EnvVars::UV_GIT_LFS).is_ok();
|
let enable_lfs_fetch = env::var(EnvVars::UV_GIT_LFS).is_ok();
|
||||||
|
|
||||||
if let Some(mut db) = db {
|
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()))?;
|
.with_context(|| format!("failed to fetch into: {}", into.user_display()))?;
|
||||||
|
|
||||||
let resolved_commit_hash = match locked_rev {
|
let resolved_commit_hash = match locked_rev {
|
||||||
|
|
@ -320,7 +321,7 @@ impl GitRemote {
|
||||||
|
|
||||||
if let Some(rev) = resolved_commit_hash {
|
if let Some(rev) = resolved_commit_hash {
|
||||||
if enable_lfs_fetch {
|
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}"))?;
|
.with_context(|| format!("failed to fetch LFS objects at {rev}"))?;
|
||||||
}
|
}
|
||||||
return Ok((db, rev));
|
return Ok((db, rev));
|
||||||
|
|
@ -338,14 +339,14 @@ impl GitRemote {
|
||||||
|
|
||||||
fs_err::create_dir_all(into)?;
|
fs_err::create_dir_all(into)?;
|
||||||
let mut repo = GitRepository::init(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()))?;
|
.with_context(|| format!("failed to clone into: {}", into.user_display()))?;
|
||||||
let rev = match locked_rev {
|
let rev = match locked_rev {
|
||||||
Some(rev) => rev,
|
Some(rev) => rev,
|
||||||
None => reference.resolve(&repo)?,
|
None => reference.resolve(&repo)?,
|
||||||
};
|
};
|
||||||
if enable_lfs_fetch {
|
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}"))?;
|
.with_context(|| format!("failed to fetch LFS objects at {rev}"))?;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -502,6 +503,7 @@ fn fetch(
|
||||||
remote_url: &Url,
|
remote_url: &Url,
|
||||||
reference: ReferenceOrOid<'_>,
|
reference: ReferenceOrOid<'_>,
|
||||||
client: &ClientWithMiddleware,
|
client: &ClientWithMiddleware,
|
||||||
|
disable_ssl: bool,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
let oid_to_fetch = match github_fast_path(repo, remote_url, reference, client) {
|
let oid_to_fetch = match github_fast_path(repo, remote_url, reference, client) {
|
||||||
Ok(FastPathRev::UpToDate) => return Ok(()),
|
Ok(FastPathRev::UpToDate) => return Ok(()),
|
||||||
|
|
@ -577,14 +579,21 @@ fn fetch(
|
||||||
|
|
||||||
debug!("Performing a Git fetch for: {remote_url}");
|
debug!("Performing a Git fetch for: {remote_url}");
|
||||||
let result = match refspec_strategy {
|
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 => {
|
RefspecStrategy::First => {
|
||||||
// Try each refspec
|
// Try each refspec
|
||||||
let mut errors = refspecs
|
let mut errors = refspecs
|
||||||
.iter()
|
.iter()
|
||||||
.map_while(|refspec| {
|
.map_while(|refspec| {
|
||||||
let fetch_result =
|
let fetch_result = fetch_with_cli(
|
||||||
fetch_with_cli(repo, remote_url, std::slice::from_ref(refspec), tags);
|
repo,
|
||||||
|
remote_url,
|
||||||
|
std::slice::from_ref(refspec),
|
||||||
|
tags,
|
||||||
|
disable_ssl,
|
||||||
|
);
|
||||||
|
|
||||||
// Stop after the first success and log failures
|
// Stop after the first success and log failures
|
||||||
match fetch_result {
|
match fetch_result {
|
||||||
|
|
@ -629,12 +638,17 @@ fn fetch_with_cli(
|
||||||
url: &Url,
|
url: &Url,
|
||||||
refspecs: &[String],
|
refspecs: &[String],
|
||||||
tags: bool,
|
tags: bool,
|
||||||
|
disable_ssl: bool,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
let mut cmd = ProcessBuilder::new(GIT.as_ref()?);
|
let mut cmd = ProcessBuilder::new(GIT.as_ref()?);
|
||||||
cmd.arg("fetch");
|
cmd.arg("fetch");
|
||||||
if tags {
|
if tags {
|
||||||
cmd.arg("--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
|
cmd.arg("--force") // handle force pushes
|
||||||
.arg("--update-head-ok") // see discussion in #2078
|
.arg("--update-head-ok") // see discussion in #2078
|
||||||
.arg(url.as_str())
|
.arg(url.as_str())
|
||||||
|
|
@ -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.
|
/// 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() {
|
let mut cmd = if let Ok(lfs) = GIT_LFS.as_ref() {
|
||||||
debug!("Fetching Git LFS objects");
|
debug!("Fetching Git LFS objects");
|
||||||
lfs.clone()
|
lfs.clone()
|
||||||
|
|
@ -684,6 +703,11 @@ fn fetch_lfs(repo: &mut GitRepository, url: &Url, revision: &GitOid) -> Result<(
|
||||||
return Ok(());
|
return Ok(());
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if disable_ssl {
|
||||||
|
debug!("Disabling SSL verification for Git LFS");
|
||||||
|
cmd.env(EnvVars::GIT_SSL_NO_VERIFY, "true");
|
||||||
|
}
|
||||||
|
|
||||||
cmd.arg("fetch")
|
cmd.arg("fetch")
|
||||||
.arg(url.as_str())
|
.arg(url.as_str())
|
||||||
.arg(revision.as_str())
|
.arg(revision.as_str())
|
||||||
|
|
|
||||||
|
|
@ -106,6 +106,7 @@ impl GitResolver {
|
||||||
&self,
|
&self,
|
||||||
url: &GitUrl,
|
url: &GitUrl,
|
||||||
client: ClientWithMiddleware,
|
client: ClientWithMiddleware,
|
||||||
|
disable_ssl: bool,
|
||||||
cache: PathBuf,
|
cache: PathBuf,
|
||||||
reporter: Option<Arc<dyn Reporter>>,
|
reporter: Option<Arc<dyn Reporter>>,
|
||||||
) -> Result<Fetch, GitResolverError> {
|
) -> Result<Fetch, GitResolverError> {
|
||||||
|
|
@ -139,6 +140,14 @@ impl GitResolver {
|
||||||
} else {
|
} else {
|
||||||
GitSource::new(url.as_ref().clone(), client, cache)
|
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())
|
let fetch = tokio::task::spawn_blocking(move || source.fetch())
|
||||||
.await?
|
.await?
|
||||||
.map_err(GitResolverError::Git)?;
|
.map_err(GitResolverError::Git)?;
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,8 @@ pub struct GitSource {
|
||||||
git: GitUrl,
|
git: GitUrl,
|
||||||
/// The HTTP client to use for fetching.
|
/// The HTTP client to use for fetching.
|
||||||
client: ClientWithMiddleware,
|
client: ClientWithMiddleware,
|
||||||
|
/// Whether to disable SSL verification.
|
||||||
|
disable_ssl: bool,
|
||||||
/// The path to the Git source database.
|
/// The path to the Git source database.
|
||||||
cache: PathBuf,
|
cache: PathBuf,
|
||||||
/// The reporter to use for this source.
|
/// The reporter to use for this source.
|
||||||
|
|
@ -37,12 +39,22 @@ impl GitSource {
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
git,
|
git,
|
||||||
|
disable_ssl: false,
|
||||||
client: client.into(),
|
client: client.into(),
|
||||||
cache: cache.into(),
|
cache: cache.into(),
|
||||||
reporter: None,
|
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`].
|
/// Set the [`Reporter`] to use for the [`GitSource`].
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn with_reporter(self, reporter: Arc<dyn Reporter>) -> Self {
|
pub fn with_reporter(self, reporter: Arc<dyn Reporter>) -> Self {
|
||||||
|
|
@ -96,6 +108,7 @@ impl GitSource {
|
||||||
&self.git.reference,
|
&self.git.reference,
|
||||||
locked_rev.map(GitOid::from),
|
locked_rev.map(GitOid::from),
|
||||||
&self.client,
|
&self.client,
|
||||||
|
self.disable_ssl,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
(db, actual_rev, task)
|
(db, actual_rev, task)
|
||||||
|
|
|
||||||
|
|
@ -449,6 +449,10 @@ impl EnvVars {
|
||||||
#[attr_hidden]
|
#[attr_hidden]
|
||||||
pub const GIT_ALTERNATE_OBJECT_DIRECTORIES: &'static str = "GIT_ALTERNATE_OBJECT_DIRECTORIES";
|
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.
|
/// Used in tests for better git isolation.
|
||||||
///
|
///
|
||||||
/// For example, we run some tests in ~/.local/share/uv/tests.
|
/// For example, we run some tests in ~/.local/share/uv/tests.
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue