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
11 changes: 6 additions & 5 deletions crates/uv-auth/src/service.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,10 @@ use uv_redacted::DisplaySafeUrl;
pub enum ServiceParseError {
#[error(transparent)]
InvalidUrl(#[from] url::ParseError),
#[error("only HTTPS (or HTTP on localhost) is supported")]
UnsupportedScheme,
#[error("Unsupported scheme: {0}")]
UnsupportedScheme(String),
#[error("HTTPS is required for non-local hosts")]
HttpsRequired,
}

/// A service URL that wraps [`DisplaySafeUrl`] for CLI usage.
Expand All @@ -36,9 +38,8 @@ impl Service {
match url.scheme() {
"https" => Ok(()),
"http" if matches!(url.host_str(), Some("localhost" | "127.0.0.1")) => Ok(()),
#[cfg(test)]
"http" => Ok(()),
Comment on lines -39 to -40
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't need a cfg for testing anymore

_ => Err(ServiceParseError::UnsupportedScheme),
"http" => Err(ServiceParseError::HttpsRequired),
value => Err(ServiceParseError::UnsupportedScheme(value.to_string())),
}
}
}
Expand Down
70 changes: 67 additions & 3 deletions crates/uv/tests/it/auth.rs
Original file line number Diff line number Diff line change
Expand Up @@ -616,7 +616,7 @@ fn login_native_auth_url() {
----- stdout -----

----- stderr -----
error: invalid value 'http://example.com' for '<SERVICE>': only HTTPS (or HTTP on localhost) is supported
error: invalid value 'http://example.com' for '<SERVICE>': HTTPS is required for non-local hosts

For more information, try '--help'.
");
Expand Down Expand Up @@ -761,7 +761,7 @@ fn login_native_auth_url() {
fn login_text_store() {
let context = TestContext::new_with_versions(&[]);

// Successful login without keyring provider (uses text store)
// Login with a username and password
uv_snapshot!(context.auth_login()
.arg("https://pypi-proxy.fly.dev/basic-auth/simple")
.arg("--username")
Expand All @@ -777,7 +777,7 @@ fn login_text_store() {
"
);

// Token-based login
// Login with a token
uv_snapshot!(context.auth_login()
.arg("https://example.com/simple")
.arg("--token")
Expand Down Expand Up @@ -822,6 +822,70 @@ fn login_text_store() {
error: Password cannot be empty
"
);

// HTTP should fail
uv_snapshot!(context.auth_login()
.arg("http://example.com/simple")
.arg("--username")
.arg("testuser")
.arg("--password")
.arg("testpass"), @r"
success: false
exit_code: 2
----- stdout -----

----- stderr -----
error: invalid value 'http://example.com/simple' for '<SERVICE>': HTTPS is required for non-local hosts

For more information, try '--help'.
");

// Other protocol should fail
uv_snapshot!(context.auth_login()
.arg("ftp://example.com/simple")
.arg("--username")
.arg("testuser")
.arg("--password")
.arg("testpass"), @r"
success: false
exit_code: 2
----- stdout -----

----- stderr -----
error: invalid value 'ftp://example.com/simple' for '<SERVICE>': Unsupported scheme: ftp

For more information, try '--help'.
");

// HTTP should be allowed on localhost
uv_snapshot!(context.auth_login()
.arg("http://127.0.0.1/simple")
.arg("--username")
.arg("testuser")
.arg("--password")
.arg("testpass"), @r"
success: true
exit_code: 0
----- stdout -----

----- stderr -----
Stored credentials for testuser@http://127.0.0.1/
");

// HTTP should be allowed on localhost
uv_snapshot!(context.auth_login()
.arg("http://localhost/simple")
.arg("--username")
.arg("testuser")
.arg("--password")
.arg("testpass"), @r"
success: true
exit_code: 0
----- stdout -----

----- stderr -----
Stored credentials for testuser@http://localhost/
");
}

#[test]
Expand Down
Loading