From 10ee2acdd26a7f1298c6f6d6b7af9b469fe29b87 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sat, 4 May 2024 14:41:41 +0200 Subject: Merging upstream version 1.70.0+dfsg2. Signed-off-by: Daniel Baumann --- src/tools/cargo/tests/testsuite/login.rs | 404 +++++++++++++++++++++++++++++++ 1 file changed, 404 insertions(+) create mode 100644 src/tools/cargo/tests/testsuite/login.rs (limited to 'src/tools/cargo/tests/testsuite/login.rs') diff --git a/src/tools/cargo/tests/testsuite/login.rs b/src/tools/cargo/tests/testsuite/login.rs new file mode 100644 index 000000000..85b299f28 --- /dev/null +++ b/src/tools/cargo/tests/testsuite/login.rs @@ -0,0 +1,404 @@ +//! Tests for the `cargo login` command. + +use cargo_test_support::cargo_process; +use cargo_test_support::paths::{self, CargoPathExt}; +use cargo_test_support::registry::{self, RegistryBuilder}; +use cargo_test_support::t; +use std::fs; +use std::path::PathBuf; + +const TOKEN: &str = "test-token"; +const TOKEN2: &str = "test-token2"; +const ORIGINAL_TOKEN: &str = "api-token"; + +fn credentials_toml() -> PathBuf { + paths::home().join(".cargo/credentials.toml") +} + +fn setup_new_credentials() { + setup_new_credentials_at(credentials_toml()); +} + +fn setup_new_credentials_at(config: PathBuf) { + t!(fs::create_dir_all(config.parent().unwrap())); + t!(fs::write( + &config, + format!(r#"token = "{token}""#, token = ORIGINAL_TOKEN) + )); +} + +/// Asserts whether or not the token is set to the given value for the given registry. +pub fn check_token(expected_token: Option<&str>, registry: Option<&str>) { + let credentials = credentials_toml(); + assert!(credentials.is_file()); + + let contents = fs::read_to_string(&credentials).unwrap(); + let toml: toml::Table = contents.parse().unwrap(); + + let actual_token = match registry { + // A registry has been provided, so check that the token exists in a + // table for the registry. + Some(registry) => toml + .get("registries") + .and_then(|registries_table| registries_table.get(registry)) + .and_then(|registry_table| match registry_table.get("token") { + Some(&toml::Value::String(ref token)) => Some(token.as_str().to_string()), + _ => None, + }), + // There is no registry provided, so check the global token instead. + None => toml + .get("registry") + .and_then(|registry_table| registry_table.get("token")) + .and_then(|v| match v { + toml::Value::String(ref token) => Some(token.as_str().to_string()), + _ => None, + }), + }; + + match (actual_token, expected_token) { + (None, None) => {} + (Some(actual), Some(expected)) => assert_eq!(actual, expected), + (None, Some(expected)) => { + panic!("expected `{registry:?}` to be `{expected}`, but was not set") + } + (Some(actual), None) => { + panic!("expected `{registry:?}` to be unset, but was set to `{actual}`") + } + } +} + +#[cargo_test] +fn registry_credentials() { + let _alternative = RegistryBuilder::new().alternative().build(); + let _alternative2 = RegistryBuilder::new() + .alternative_named("alternative2") + .build(); + + setup_new_credentials(); + + let reg = "alternative"; + + cargo_process("login --registry").arg(reg).arg(TOKEN).run(); + + // Ensure that we have not updated the default token + check_token(Some(ORIGINAL_TOKEN), None); + + // Also ensure that we get the new token for the registry + check_token(Some(TOKEN), Some(reg)); + + let reg2 = "alternative2"; + cargo_process("login --registry") + .arg(reg2) + .arg(TOKEN2) + .run(); + + // Ensure not overwriting 1st alternate registry token with + // 2nd alternate registry token (see rust-lang/cargo#7701). + check_token(Some(ORIGINAL_TOKEN), None); + check_token(Some(TOKEN), Some(reg)); + check_token(Some(TOKEN2), Some(reg2)); +} + +#[cargo_test] +fn empty_login_token() { + let registry = RegistryBuilder::new() + .no_configure_registry() + .no_configure_token() + .build(); + setup_new_credentials(); + + cargo_process("login") + .replace_crates_io(registry.index_url()) + .with_stdout("please paste the token found on [..]/me below") + .with_stdin("\t\n") + .with_stderr( + "\ +[UPDATING] crates.io index +[ERROR] please provide a non-empty token +", + ) + .with_status(101) + .run(); + + cargo_process("login") + .replace_crates_io(registry.index_url()) + .arg("") + .with_stderr( + "\ +[ERROR] please provide a non-empty token +", + ) + .with_status(101) + .run(); +} + +#[cargo_test] +fn invalid_login_token() { + let registry = RegistryBuilder::new() + .no_configure_registry() + .no_configure_token() + .build(); + setup_new_credentials(); + + let check = |stdin: &str, stderr: &str, status: i32| { + cargo_process("login") + .replace_crates_io(registry.index_url()) + .with_stdout("please paste the token found on [..]/me below") + .with_stdin(stdin) + .with_stderr(stderr) + .with_status(status) + .run(); + }; + + let invalid = |stdin: &str| { + check( + stdin, + "[ERROR] token contains invalid characters. +Only printable ISO-8859-1 characters are allowed as it is sent in a HTTPS header.", + 101, + ) + }; + let valid = |stdin: &str| check(stdin, "[LOGIN] token for `crates.io` saved", 0); + + // Update config.json so that the rest of the tests don't need to care + // whether or not `Updating` is printed. + check( + "test", + "\ +[UPDATING] crates.io index +[LOGIN] token for `crates.io` saved +", + 0, + ); + + invalid("😄"); + invalid("\u{0016}"); + invalid("\u{0000}"); + invalid("你好"); + valid("foo\tbar"); + valid("foo bar"); + valid( + r##"!"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~"##, + ); +} + +#[cargo_test] +fn bad_asymmetric_token_args() { + // These cases are kept brief as the implementation is covered by clap, so this is only smoke testing that we have clap configured correctly. + cargo_process("login --key-subject=foo tok") + .with_stderr_contains( + "error: the argument '--key-subject ' cannot be used with '[token]'", + ) + .with_status(1) + .run(); + + cargo_process("login --generate-keypair tok") + .with_stderr_contains( + "error: the argument '--generate-keypair' cannot be used with '[token]'", + ) + .with_status(1) + .run(); + + cargo_process("login --secret-key tok") + .with_stderr_contains("error: the argument '--secret-key' cannot be used with '[token]'") + .with_status(1) + .run(); + + cargo_process("login --generate-keypair --secret-key") + .with_stderr_contains( + "error: the argument '--generate-keypair' cannot be used with '--secret-key'", + ) + .with_status(1) + .run(); +} + +#[cargo_test] +fn asymmetric_requires_nightly() { + let registry = registry::init(); + cargo_process("login --key-subject=foo") + .replace_crates_io(registry.index_url()) + .with_status(101) + .with_stderr_contains("[ERROR] the `key-subject` flag is unstable, pass `-Z registry-auth` to enable it\n\ + See https://github.com/rust-lang/cargo/issues/10519 for more information about the `key-subject` flag.") + .run(); + cargo_process("login --generate-keypair") + .replace_crates_io(registry.index_url()) + .with_status(101) + .with_stderr_contains("[ERROR] the `generate-keypair` flag is unstable, pass `-Z registry-auth` to enable it\n\ + See https://github.com/rust-lang/cargo/issues/10519 for more information about the `generate-keypair` flag.") + .run(); + cargo_process("login --secret-key") + .replace_crates_io(registry.index_url()) + .with_status(101) + .with_stderr_contains("[ERROR] the `secret-key` flag is unstable, pass `-Z registry-auth` to enable it\n\ + See https://github.com/rust-lang/cargo/issues/10519 for more information about the `secret-key` flag.") + .run(); +} + +#[cargo_test] +fn login_with_no_cargo_dir() { + // Create a config in the root directory because `login` requires the + // index to be updated, and we don't want to hit crates.io. + let registry = registry::init(); + fs::rename(paths::home().join(".cargo"), paths::root().join(".cargo")).unwrap(); + paths::home().rm_rf(); + cargo_process("login foo -v") + .replace_crates_io(registry.index_url()) + .run(); + let credentials = fs::read_to_string(credentials_toml()).unwrap(); + assert_eq!(credentials, "[registry]\ntoken = \"foo\"\n"); +} + +#[cargo_test] +fn login_with_differently_sized_token() { + // Verify that the configuration file gets properly truncated. + let registry = registry::init(); + let credentials = credentials_toml(); + fs::remove_file(&credentials).unwrap(); + cargo_process("login lmaolmaolmao -v") + .replace_crates_io(registry.index_url()) + .run(); + cargo_process("login lmao -v") + .replace_crates_io(registry.index_url()) + .run(); + cargo_process("login lmaolmaolmao -v") + .replace_crates_io(registry.index_url()) + .run(); + let credentials = fs::read_to_string(&credentials).unwrap(); + assert_eq!(credentials, "[registry]\ntoken = \"lmaolmaolmao\"\n"); +} + +#[cargo_test] +fn login_with_token_on_stdin() { + let registry = registry::init(); + let credentials = credentials_toml(); + fs::remove_file(&credentials).unwrap(); + cargo_process("login lmao -v") + .replace_crates_io(registry.index_url()) + .run(); + cargo_process("login") + .replace_crates_io(registry.index_url()) + .with_stdout("please paste the token found on [..]/me below") + .with_stdin("some token") + .run(); + let credentials = fs::read_to_string(&credentials).unwrap(); + assert_eq!(credentials, "[registry]\ntoken = \"some token\"\n"); +} + +#[cargo_test] +fn login_with_asymmetric_token_and_subject_on_stdin() { + let registry = registry::init(); + let credentials = credentials_toml(); + fs::remove_file(&credentials).unwrap(); + cargo_process("login --key-subject=foo --secret-key -v -Z registry-auth") + .masquerade_as_nightly_cargo(&["registry-auth"]) + .replace_crates_io(registry.index_url()) + .with_stdout( + "\ + please paste the API secret key below +k3.public.AmDwjlyf8jAV3gm5Z7Kz9xAOcsKslt_Vwp5v-emjFzBHLCtcANzTaVEghTNEMj9PkQ", + ) + .with_stdin("k3.secret.fNYVuMvBgOlljt9TDohnaYLblghqaHoQquVZwgR6X12cBFHZLFsaU3q7X3k1Zn36") + .run(); + let credentials = fs::read_to_string(&credentials).unwrap(); + assert!(credentials.starts_with("[registry]\n")); + assert!(credentials.contains("secret-key-subject = \"foo\"\n")); + assert!(credentials.contains("secret-key = \"k3.secret.fNYVuMvBgOlljt9TDohnaYLblghqaHoQquVZwgR6X12cBFHZLFsaU3q7X3k1Zn36\"\n")); +} + +#[cargo_test] +fn login_with_asymmetric_token_on_stdin() { + let registry = registry::init(); + let credentials = credentials_toml(); + fs::remove_file(&credentials).unwrap(); + cargo_process("login --secret-key -v -Z registry-auth") + .masquerade_as_nightly_cargo(&["registry-auth"]) + .replace_crates_io(registry.index_url()) + .with_stdout( + "\ + please paste the API secret key below +k3.public.AmDwjlyf8jAV3gm5Z7Kz9xAOcsKslt_Vwp5v-emjFzBHLCtcANzTaVEghTNEMj9PkQ", + ) + .with_stdin("k3.secret.fNYVuMvBgOlljt9TDohnaYLblghqaHoQquVZwgR6X12cBFHZLFsaU3q7X3k1Zn36") + .run(); + let credentials = fs::read_to_string(&credentials).unwrap(); + assert_eq!(credentials, "[registry]\nsecret-key = \"k3.secret.fNYVuMvBgOlljt9TDohnaYLblghqaHoQquVZwgR6X12cBFHZLFsaU3q7X3k1Zn36\"\n"); +} + +#[cargo_test] +fn login_with_asymmetric_key_subject_without_key() { + let registry = registry::init(); + let credentials = credentials_toml(); + fs::remove_file(&credentials).unwrap(); + cargo_process("login --key-subject=foo -Z registry-auth") + .masquerade_as_nightly_cargo(&["registry-auth"]) + .replace_crates_io(registry.index_url()) + .with_stderr_contains("error: need a secret_key to set a key_subject") + .with_status(101) + .run(); + + // ok so add a secret_key to the credentials + cargo_process("login --secret-key -v -Z registry-auth") + .masquerade_as_nightly_cargo(&["registry-auth"]) + .replace_crates_io(registry.index_url()) + .with_stdout( + "please paste the API secret key below +k3.public.AmDwjlyf8jAV3gm5Z7Kz9xAOcsKslt_Vwp5v-emjFzBHLCtcANzTaVEghTNEMj9PkQ", + ) + .with_stdin("k3.secret.fNYVuMvBgOlljt9TDohnaYLblghqaHoQquVZwgR6X12cBFHZLFsaU3q7X3k1Zn36") + .run(); + + // and then it should work + cargo_process("login --key-subject=foo -Z registry-auth") + .masquerade_as_nightly_cargo(&["registry-auth"]) + .replace_crates_io(registry.index_url()) + .run(); + + let credentials = fs::read_to_string(&credentials).unwrap(); + assert!(credentials.starts_with("[registry]\n")); + assert!(credentials.contains("secret-key-subject = \"foo\"\n")); + assert!(credentials.contains("secret-key = \"k3.secret.fNYVuMvBgOlljt9TDohnaYLblghqaHoQquVZwgR6X12cBFHZLFsaU3q7X3k1Zn36\"\n")); +} + +#[cargo_test] +fn login_with_generate_asymmetric_token() { + let registry = registry::init(); + let credentials = credentials_toml(); + fs::remove_file(&credentials).unwrap(); + cargo_process("login --generate-keypair -Z registry-auth") + .masquerade_as_nightly_cargo(&["registry-auth"]) + .replace_crates_io(registry.index_url()) + .with_stdout("k3.public.[..]") + .run(); + let credentials = fs::read_to_string(&credentials).unwrap(); + assert!(credentials.contains("secret-key = \"k3.secret.")); +} + +#[cargo_test] +fn default_registry_configured() { + // When registry.default is set, login should use that one when + // --registry is not used. + let _alternative = RegistryBuilder::new().alternative().build(); + let cargo_home = paths::home().join(".cargo"); + cargo_util::paths::append( + &cargo_home.join("config"), + br#" + [registry] + default = "alternative" + "#, + ) + .unwrap(); + + cargo_process("login") + .arg("a-new-token") + .with_stderr( + "\ +[UPDATING] `alternative` index +[LOGIN] token for `alternative` saved +", + ) + .run(); + + check_token(None, None); + check_token(Some("a-new-token"), Some("alternative")); +} -- cgit v1.2.3