From 33c91159c61a889d3858eb4e565255d08e1a3377 Mon Sep 17 00:00:00 2001 From: Zanie Blue Date: Tue, 13 Jan 2026 16:31:06 -0600 Subject: [PATCH] Use keyring authentication when retrieving `tool@latest` version (#17448) Closes #17436 Co-authored-by: Claude --- crates/uv/src/commands/tool/install.rs | 17 +++++--- crates/uv/src/commands/tool/run.rs | 17 +++++--- crates/uv/tests/it/tool_run.rs | 56 +++++++++++++++++++++++++- 3 files changed, 77 insertions(+), 13 deletions(-) diff --git a/crates/uv/src/commands/tool/install.rs b/crates/uv/src/commands/tool/install.rs index 48a7fd9cc..113efdc87 100644 --- a/crates/uv/src/commands/tool/install.rs +++ b/crates/uv/src/commands/tool/install.rs @@ -241,12 +241,17 @@ pub(crate) async fn install( } = &request { // Build the registry client to fetch the latest version. - let client = RegistryClientBuilder::new(client_builder.clone(), cache.clone()) - .index_locations(settings.resolver.index_locations.clone()) - .index_strategy(settings.resolver.index_strategy) - .markers(interpreter.markers()) - .platform(interpreter.platform()) - .build(); + let client = RegistryClientBuilder::new( + client_builder + .clone() + .keyring(settings.resolver.keyring_provider), + cache.clone(), + ) + .index_locations(settings.resolver.index_locations.clone()) + .index_strategy(settings.resolver.index_strategy) + .markers(interpreter.markers()) + .platform(interpreter.platform()) + .build(); // Initialize the capabilities. let capabilities = IndexCapabilities::default(); diff --git a/crates/uv/src/commands/tool/run.rs b/crates/uv/src/commands/tool/run.rs index 60e96f3f8..b2c3b9a15 100644 --- a/crates/uv/src/commands/tool/run.rs +++ b/crates/uv/src/commands/tool/run.rs @@ -918,12 +918,17 @@ async fn get_or_create_environment( } = &request { // Build the registry client to fetch the latest version. - let client = RegistryClientBuilder::new(client_builder.clone(), cache.clone()) - .index_locations(settings.resolver.index_locations.clone()) - .index_strategy(settings.resolver.index_strategy) - .markers(interpreter.markers()) - .platform(interpreter.platform()) - .build(); + let client = RegistryClientBuilder::new( + client_builder + .clone() + .keyring(settings.resolver.keyring_provider), + cache.clone(), + ) + .index_locations(settings.resolver.index_locations.clone()) + .index_strategy(settings.resolver.index_strategy) + .markers(interpreter.markers()) + .platform(interpreter.platform()) + .build(); // Initialize the capabilities. let capabilities = IndexCapabilities::default(); diff --git a/crates/uv/tests/it/tool_run.rs b/crates/uv/tests/it/tool_run.rs index 9eb71af7d..a92c1a330 100644 --- a/crates/uv/tests/it/tool_run.rs +++ b/crates/uv/tests/it/tool_run.rs @@ -1,4 +1,4 @@ -use crate::common::{TestContext, uv_snapshot}; +use crate::common::{TestContext, uv_snapshot, venv_bin_path}; use anyhow::Result; use assert_cmd::prelude::*; use assert_fs::prelude::*; @@ -3506,3 +3506,57 @@ fn tool_run_windows_dotted_package_name() -> anyhow::Result<()> { Ok(()) } + +/// Regression test for +#[test] +fn tool_run_latest_keyring_auth() { + let keyring_context = TestContext::new("3.12"); + + // Install our keyring plugin + keyring_context + .pip_install() + .arg( + keyring_context + .workspace_root + .join("test") + .join("packages") + .join("keyring_test_plugin"), + ) + .assert() + .success(); + + let context = TestContext::new("3.12") + .with_exclude_newer("2025-01-18T00:00:00Z") + .with_filtered_counts(); + let tool_dir = context.temp_dir.child("tools"); + let bin_dir = context.temp_dir.child("bin"); + + // Combine keyring venv bin with tool bin directory to avoid PATH warnings. + let path = std::env::join_paths([venv_bin_path(&keyring_context.venv), bin_dir.to_path_buf()]) + .unwrap(); + + // Test that the keyring is consulted during the @latest version lookup. + uv_snapshot!(context.filters(), context.tool_install() + .arg("--index") + .arg("https://public@pypi-proxy.fly.dev/basic-auth/simple") + .arg("--keyring-provider") + .arg("subprocess") + .arg("executable-application@latest") + .env(EnvVars::UV_TOOL_DIR, tool_dir.as_os_str()) + .env(EnvVars::XDG_BIN_HOME, bin_dir.as_os_str()) + .env(EnvVars::KEYRING_TEST_CREDENTIALS, r#"{"pypi-proxy.fly.dev": {"public": "heron"}}"#) + .env(EnvVars::PATH, path), @r###" + success: true + exit_code: 0 + ----- stdout ----- + + ----- stderr ----- + Keyring request for public@https://pypi-proxy.fly.dev/basic-auth/simple + Keyring request for public@pypi-proxy.fly.dev + Resolved [N] packages in [TIME] + Prepared [N] packages in [TIME] + Installed [N] packages in [TIME] + + executable-application==0.3.0 + Installed 1 executable: app + "###); +}