Misc. tweaks

This commit is contained in:
Charlie Marsh 2025-08-30 14:25:27 -04:00 committed by Zanie Blue
parent 32bcfdff0a
commit 7d9446450b
12 changed files with 29 additions and 34 deletions

View File

@ -80,10 +80,12 @@ impl Password {
Self(password)
}
/// Return the [`Password`] as a string slice.
pub fn as_str(&self) -> &str {
self.0.as_str()
}
/// Convert the [`Password`] into its underlying [`String`].
pub fn into_string(self) -> String {
self.0
}

View File

@ -159,11 +159,11 @@ impl KeyringProvider {
// Validate the request
debug_assert!(
url.host_str().is_some(),
"Should only use keyring for urls with host"
"Should only use keyring for URLs with host"
);
debug_assert!(
url.password().is_none(),
"Should only use keyring for urls without a password"
"Should only use keyring for URLs without a password"
);
debug_assert!(
!username.map(str::is_empty).unwrap_or(false),
@ -286,7 +286,7 @@ impl KeyringProvider {
// N.B. We do not show the `service_name` here because we'll show the warning twice
// otherwise, once for the URL and once for the realm.
warn_user_once!(
"Attempted to fetch credentials using the `keyring` command, but it does not support `--mode creds`; upgrade to `keyring>=v25.2.1` for support or provide a username"
"Attempted to fetch credentials using the `keyring` command, but it does not support `--mode creds`; upgrade to `keyring>=v25.2.1` or provide a username"
);
} else if username.is_none() {
// If we captured stderr, display it in case it's helpful to the user
@ -314,8 +314,7 @@ impl KeyringProvider {
}
Err(err) => {
warn_user_once!(
"Unable to fetch credentials for {service} from system keyring: {}",
err
"Unable to fetch credentials for {service} from system keyring: {err}"
);
}
}

View File

@ -94,7 +94,7 @@ impl Default for TextStoreMode {
}
impl TextStoreMode {
/// Get the parsed credential store if enabled.
/// Get the parsed credential store, if enabled.
fn get(&self) -> Option<&TextCredentialStore> {
match self {
Self::Automatic(lock) => lock.as_ref(),

View File

@ -1,11 +1,12 @@
use serde::{Deserialize, Serialize};
use std::str::FromStr;
use thiserror::Error;
use url::Url;
use uv_redacted::DisplaySafeUrl;
#[derive(Error, Debug)]
pub enum ServiceParseError {
#[error("failed to parse URL: {0}")]
#[error(transparent)]
InvalidUrl(#[from] url::ParseError),
#[error("only HTTPS is supported")]
UnsupportedScheme,
@ -31,7 +32,7 @@ impl Service {
}
/// Validate that the URL scheme is supported.
fn check_scheme(url: &DisplaySafeUrl) -> Result<(), ServiceParseError> {
fn check_scheme(url: &Url) -> Result<(), ServiceParseError> {
match url.scheme() {
"https" => Ok(()),
#[cfg(test)]

View File

@ -18,12 +18,13 @@ use crate::realm::Realm;
use crate::service::Service;
/// Authentication scheme to use.
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
#[derive(Debug, Default, Copy, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum AuthScheme {
/// HTTP Basic Authentication
///
/// Uses a username and password.
#[default]
Basic,
/// Bearer token authentication.
///
@ -31,12 +32,6 @@ pub enum AuthScheme {
Bearer,
}
impl Default for AuthScheme {
fn default() -> Self {
Self::Basic
}
}
/// Errors that can occur when working with TOML credential storage.
#[derive(Debug, Error)]
pub enum TomlCredentialError {
@ -75,11 +70,11 @@ pub enum BearerAuthError {
}
/// A single credential entry in a TOML credentials file.
// TODO(zanieb): It's a little clunky that we need don't nest the scheme-specific fields under a
// TODO(zanieb): It's a little clunky that we need don't nest the scheme-specific fields under
// that scheme, but I want the username / password case to be easily accessible without
// understanding authentication schemes. We should consider a better structure here, e.g., by
// adding an internal type that we cast to after validation.
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TomlCredential {
/// The service URL for this credential.
pub service: Service,
@ -172,10 +167,10 @@ impl TomlCredential {
}
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct TomlCredentials {
struct TomlCredentials {
/// Array of credential entries.
#[serde(rename = "credential")]
pub credentials: Vec<TomlCredential>,
credentials: Vec<TomlCredential>,
}
/// A credential store with a plain text storage backend.
@ -215,8 +210,8 @@ impl TextCredentialStore {
// TODO(zanieb): Determine a better strategy for invalid credential entries
if let Err(err) = credential.validate() {
debug!(
"Skipping invalid credential for {}: {}",
credential.service, err
"Skipping invalid credential for {}: {err}",
credential.service
);
return None;
}

View File

@ -5548,7 +5548,7 @@ pub struct AuthLogoutArgs {
#[derive(Args)]
pub struct AuthLoginArgs {
/// The service to login to.
/// The service to log into.
pub service: Service,
/// The username to use for the service.

View File

@ -24,15 +24,14 @@ pub(crate) async fn login(
printer: Printer,
preview: Preview,
) -> Result<ExitStatus> {
let service_clone = service.clone();
let url = service_clone.url();
let backend = AuthBackend::from_settings(keyring_provider.as_ref(), preview)?;
// If the URL includes a known index URL suffix, strip it
// TODO(zanieb): Use a shared abstraction across `login` and `logout`?
let url = service.url().clone();
let (service, url) = match IndexUrl::from(VerbatimUrl::from_url(url.clone())).root() {
Some(root) => (Service::try_from(root.clone())?, root),
None => (service, url.clone()),
None => (service, url),
};
// Extract credentials from URL if present
@ -125,7 +124,7 @@ pub(crate) async fn login(
writeln!(
printer.stderr(),
"Stored credentials for {}",
display_url.cyan()
display_url.bold().cyan()
)?;
Ok(ExitStatus::Success)
}

View File

@ -23,14 +23,13 @@ pub(crate) async fn logout(
printer: Printer,
preview: Preview,
) -> Result<ExitStatus> {
let service_clone = service.clone();
let url = service_clone.url();
let backend = AuthBackend::from_settings(keyring_provider.as_ref(), preview)?;
// TODO(zanieb): Use a shared abstraction across `login` and `logout`?
let url = service.url().clone();
let (service, url) = match IndexUrl::from(VerbatimUrl::from_url(url.clone())).root() {
Some(root) => (Service::try_from(root.clone())?, root),
None => (service, url.clone()),
None => (service, url),
};
// Extract credentials from URL if present
@ -75,7 +74,7 @@ pub(crate) async fn logout(
writeln!(
printer.stderr(),
"Removed credentials for {}",
display_url.cyan()
display_url.bold().cyan()
)?;
Ok(ExitStatus::Success)

View File

@ -18,8 +18,8 @@ pub(crate) async fn token(
printer: Printer,
preview: Preview,
) -> Result<ExitStatus> {
let url = service.url();
let backend = AuthBackend::from_settings(keyring_provider.as_ref(), preview)?;
let url = service.url();
// Extract credentials from URL if present
let url_credentials = Credentials::from_url(url);

View File

@ -815,7 +815,7 @@ fn login_native_keyring_url() {
----- stdout -----
----- stderr -----
error: invalid value 'not a valid url' for '<SERVICE>': failed to parse URL: invalid international domain name
error: invalid value 'not a valid url' for '<SERVICE>': invalid international domain name
For more information, try '--help'.
");

View File

@ -21067,7 +21067,7 @@ fn lock_keyring_credentials_always_authenticate_unsupported_mode() -> Result<()>
----- stdout -----
----- stderr -----
warning: Attempted to fetch credentials using the `keyring` command, but it does not support `--mode creds`; upgrade to `keyring>=v25.2.1` for support or provide a username
warning: Attempted to fetch credentials using the `keyring` command, but it does not support `--mode creds`; upgrade to `keyring>=v25.2.1` or provide a username
error: Failed to fetch: `https://pypi-proxy.fly.dev/basic-auth/simple/iniconfig/`
Caused by: Missing credentials for https://pypi-proxy.fly.dev/basic-auth/simple/iniconfig/
");

View File

@ -63,7 +63,7 @@ uv auth login [OPTIONS] <SERVICE>
<h3 class="cli-reference">Arguments</h3>
<dl class="cli-reference"><dt id="uv-auth-login--service"><a href="#uv-auth-login--service"<code>SERVICE</code></a></dt><dd><p>The service to login to</p>
<dl class="cli-reference"><dt id="uv-auth-login--service"><a href="#uv-auth-login--service"<code>SERVICE</code></a></dt><dd><p>The service to log into</p>
</dd></dl>
<h3 class="cli-reference">Options</h3>