Skip to content

Commit

Permalink
Add integration test coverage for keyring authentication (#3067)
Browse files Browse the repository at this point in the history
Closes #2464
  • Loading branch information
zanieb committed Apr 17, 2024
1 parent e5d4ea5 commit 7c5b13c
Show file tree
Hide file tree
Showing 5 changed files with 178 additions and 1 deletion.
10 changes: 10 additions & 0 deletions crates/uv/tests/common/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -309,6 +309,16 @@ fn site_packages_path(venv: &Path, python: String) -> PathBuf {
}
}

pub fn venv_bin_path(venv: &Path) -> PathBuf {
if cfg!(unix) {
venv.join("bin")
} else if cfg!(windows) {
venv.join("Scripts")
} else {
unimplemented!("Only Windows and Unix are supported")
}
}

pub fn venv_to_interpreter(venv: &Path) -> PathBuf {
if cfg!(unix) {
venv.join("bin").join("python")
Expand Down
124 changes: 123 additions & 1 deletion crates/uv/tests/pip_install.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ use itertools::Itertools;
use common::{uv_snapshot, TestContext};
use uv_fs::Simplified;

use crate::common::{get_bin, BUILD_VENDOR_LINKS_URL};
use crate::common::{get_bin, venv_bin_path, BUILD_VENDOR_LINKS_URL};

mod common;

Expand Down Expand Up @@ -2916,6 +2916,128 @@ fn install_index_with_relative_links() {
context.assert_command("import anyio").success();
}

/// Install a package from an index that requires authentication from the keyring.
#[test]
fn install_package_basic_auth_from_keyring() {
let context = TestContext::new("3.12");

// Install our keyring plugin
context
.install()
.arg(
context
.workspace_root
.join("scripts")
.join("packages")
.join("keyring_test_plugin"),
)
.assert()
.success();

uv_snapshot!(context.install()
.arg("anyio")
.arg("--index-url")
.arg("https://[email protected]/basic-auth/simple")
.arg("--keyring-provider")
.arg("subprocess")
.arg("--strict")
.env("KEYRING_TEST_CREDENTIALS", r#"{"pypi-proxy.fly.dev": {"public": "heron"}}"#)
.env("PATH", venv_bin_path(context.venv.as_path())), @r###"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Resolved 3 packages in [TIME]
Downloaded 3 packages in [TIME]
Installed 3 packages in [TIME]
+ anyio==4.3.0
+ idna==3.6
+ sniffio==1.3.1
"###
);

context.assert_command("import anyio").success();
}

/// Install a package from an index that requires authentication
/// but the keyring has the wrong password
#[test]
fn install_package_basic_auth_from_keyring_wrong_password() {
let context = TestContext::new("3.12");

// Install our keyring plugin
context
.install()
.arg(
context
.workspace_root
.join("scripts")
.join("packages")
.join("keyring_test_plugin"),
)
.assert()
.success();

uv_snapshot!(context.install()
.arg("anyio")
.arg("--index-url")
.arg("https://[email protected]/basic-auth/simple")
.arg("--keyring-provider")
.arg("subprocess")
.arg("--strict")
.env("KEYRING_TEST_CREDENTIALS", r#"{"pypi-proxy.fly.dev": {"public": "foobar"}}"#)
.env("PATH", venv_bin_path(context.venv.as_path())), @r###"
success: false
exit_code: 2
----- stdout -----
----- stderr -----
error: Failed to download: anyio==4.3.0
Caused by: HTTP status client error (401 Unauthorized) for url (https://pypi-proxy.fly.dev/basic-auth/files/packages/14/fd/2f20c40b45e4fb4324834aea24bd4afdf1143390242c0b33774da0e2e34f/anyio-4.3.0-py3-none-any.whl.metadata)
"###
);
}

/// Install a package from an index that requires authentication
/// but the keyring has the wrong username
#[test]
fn install_package_basic_auth_from_keyring_wrong_username() {
let context = TestContext::new("3.12");

// Install our keyring plugin
context
.install()
.arg(
context
.workspace_root
.join("scripts")
.join("packages")
.join("keyring_test_plugin"),
)
.assert()
.success();

uv_snapshot!(context.install()
.arg("anyio")
.arg("--index-url")
.arg("https://[email protected]/basic-auth/simple")
.arg("--keyring-provider")
.arg("subprocess")
.arg("--strict")
.env("KEYRING_TEST_CREDENTIALS", r#"{"pypi-proxy.fly.dev": {"other": "heron"}}"#)
.env("PATH", venv_bin_path(context.venv.as_path())), @r###"
success: false
exit_code: 2
----- stdout -----
----- stderr -----
error: Failed to download: anyio==4.3.0
Caused by: HTTP status client error (401 Unauthorized) for url (https://pypi-proxy.fly.dev/basic-auth/files/packages/14/fd/2f20c40b45e4fb4324834aea24bd4afdf1143390242c0b33774da0e2e34f/anyio-4.3.0-py3-none-any.whl.metadata)
"###
);
}

/// Install a package from an index that provides relative links and requires authentication
#[test]
fn install_index_with_relative_links_authenticated() {
Expand Down
Empty file.
23 changes: 23 additions & 0 deletions scripts/packages/keyring_test_plugin/keyrings/test_keyring.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import json
import os
import sys

from keyring import backend


class KeyringTest(backend.KeyringBackend):
priority = 9

def get_password(self, service, username):
print(f"Request for {username}@{service}", file=sys.stderr)
credentials = json.loads(os.environ.get("KEYRING_TEST_CREDENTIALS") or {})
return credentials.get(service, {}).get(username)

def set_password(self, service, username, password):
raise NotImplementedError()

def delete_password(self, service, username):
raise NotImplementedError()

def get_credential(self, service, username):
raise NotImplementedError()
22 changes: 22 additions & 0 deletions scripts/packages/keyring_test_plugin/pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
[build-system]
requires = ["flit_core >=3.2,<4"]
build-backend = "flit_core.buildapi"

[project]
name = "keyring-test-plugin"
description = "A keyring plugin for testing."
requires-python = ">=3.7"
version = "0.1.0"
keywords = []
authors = [
{ name = "Astral Software Inc.", email = "[email protected]" },
]
dependencies = [
"keyring"
]

[tool.flit.module]
name = "keyrings"

[project.entry-points."keyring.backends"]
AstralTest = "keyrings.test_keyring"

0 comments on commit 7c5b13c

Please sign in to comment.