Eagerly reject unsupported Git schemes (#11514)

Initially, we were limiting Git schemes to HTTPS and SSH as only
supported schemes. We lost this validation in #3429. This incidentally
allowed file schemes, which apparently work with Git out of the box.

A caveat for this is that in tool.uv.sources, we parse the git field
always as URL. This caused a problem with #11425: repo = { git =
'c:\path\to\repo', rev = "xxxxx" } was parsed as a URL where c: is the
scheme, causing a bad error message down the line.

This PR:

* Puts Git URL validation back in place. It bans everything but HTTPS,
SSH, and file URLs. This could be a breaking change, if users were using
a git transport protocol were not aware of, even though never
intentionally supported.
* Allows file: URL in Git: This seems to be supported by Git and we were
supporting it albeit unintentionally, so it's reasonable to continue to
support it.
* It does not allow relative paths in the git field in tool.uv.sources.
Absolute file URLs are supported, whether we want relative file URLs for
Git too should be discussed separately.

Closes #3429: We reject the input with a proper error message, while
hinting the user towards file:. If there's still desire for relative
path support, we can keep it open.

---------

Co-authored-by: Charlie Marsh <charlie.r.marsh@gmail.com>
This commit is contained in:
konsti
2025-02-18 03:14:06 +01:00
committed by GitHub
parent 8c3a6b2155
commit 29c2be3e97
18 changed files with 212 additions and 171 deletions
+43 -12
View File
@@ -1,12 +1,22 @@
pub use crate::github::GitHubRepository;
pub use crate::oid::{GitOid, OidParseError};
pub use crate::reference::GitReference;
use thiserror::Error;
use url::Url;
mod github;
mod oid;
mod reference;
#[derive(Debug, Error)]
pub enum GitUrlParseError {
#[error(
"Unsupported Git URL scheme `{0}:` in `{1}` (expected one of `https:`, `ssh:`, or `file:`)"
)]
UnsupportedGitScheme(String, Url),
}
/// A URL reference to a Git repository.
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Hash, Ord)]
pub struct GitUrl {
@@ -21,21 +31,42 @@ pub struct GitUrl {
impl GitUrl {
/// Create a new [`GitUrl`] from a repository URL and a reference.
pub fn from_reference(repository: Url, reference: GitReference) -> Self {
Self {
repository,
reference,
precise: None,
}
pub fn from_reference(
repository: Url,
reference: GitReference,
) -> Result<Self, GitUrlParseError> {
Self::from_fields(repository, reference, None)
}
/// Create a new [`GitUrl`] from a repository URL and a precise commit.
pub fn from_commit(repository: Url, reference: GitReference, precise: GitOid) -> Self {
Self {
pub fn from_commit(
repository: Url,
reference: GitReference,
precise: GitOid,
) -> Result<Self, GitUrlParseError> {
Self::from_fields(repository, reference, Some(precise))
}
/// Create a new [`GitUrl`] from a repository URL and a precise commit, if known.
pub fn from_fields(
repository: Url,
reference: GitReference,
precise: Option<GitOid>,
) -> Result<Self, GitUrlParseError> {
match repository.scheme() {
"https" | "ssh" | "file" => {}
unsupported => {
return Err(GitUrlParseError::UnsupportedGitScheme(
unsupported.to_string(),
repository,
))
}
}
Ok(Self {
repository,
reference,
precise: Some(precise),
}
precise,
})
}
/// Set the precise [`GitOid`] to use for this Git URL.
@@ -69,7 +100,7 @@ impl GitUrl {
}
impl TryFrom<Url> for GitUrl {
type Error = OidParseError;
type Error = GitUrlParseError;
/// Initialize a [`GitUrl`] source from a URL.
fn try_from(mut url: Url) -> Result<Self, Self::Error> {
@@ -89,7 +120,7 @@ impl TryFrom<Url> for GitUrl {
url.set_path(&prefix);
}
Ok(Self::from_reference(url, reference))
Self::from_reference(url, reference)
}
}