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 --- .../cargo/tests/testsuite/credential_process.rs | 504 +++++++++++++++++++++ 1 file changed, 504 insertions(+) create mode 100644 src/tools/cargo/tests/testsuite/credential_process.rs (limited to 'src/tools/cargo/tests/testsuite/credential_process.rs') diff --git a/src/tools/cargo/tests/testsuite/credential_process.rs b/src/tools/cargo/tests/testsuite/credential_process.rs new file mode 100644 index 000000000..8c202c6a3 --- /dev/null +++ b/src/tools/cargo/tests/testsuite/credential_process.rs @@ -0,0 +1,504 @@ +//! Tests for credential-process. + +use cargo_test_support::registry::TestRegistry; +use cargo_test_support::{basic_manifest, cargo_process, paths, project, registry, Project}; +use std::fs::{self, read_to_string}; + +fn toml_bin(proj: &Project, name: &str) -> String { + proj.bin(name).display().to_string().replace('\\', "\\\\") +} + +#[cargo_test] +fn gated() { + let _alternative = registry::RegistryBuilder::new() + .alternative() + .no_configure_token() + .build(); + + let cratesio = registry::RegistryBuilder::new() + .no_configure_token() + .build(); + + let p = project() + .file( + ".cargo/config", + r#" + [registry] + credential-process = "false" + "#, + ) + .file("Cargo.toml", &basic_manifest("foo", "1.0.0")) + .file("src/lib.rs", "") + .build(); + + p.cargo("publish --no-verify") + .replace_crates_io(cratesio.index_url()) + .masquerade_as_nightly_cargo(&["credential-process"]) + .with_status(101) + .with_stderr( + "\ +[UPDATING] [..] +[ERROR] no token found, please run `cargo login` +or use environment variable CARGO_REGISTRY_TOKEN +", + ) + .run(); + + p.change_file( + ".cargo/config", + r#" + [registry.alternative] + credential-process = "false" + "#, + ); + + p.cargo("publish --no-verify --registry alternative") + .masquerade_as_nightly_cargo(&["credential-process"]) + .with_status(101) + .with_stderr( + "\ +[UPDATING] [..] +[ERROR] no token found for `alternative`, please run `cargo login --registry alternative` +or use environment variable CARGO_REGISTRIES_ALTERNATIVE_TOKEN +", + ) + .run(); +} + +#[cargo_test] +fn warn_both_token_and_process() { + // Specifying both credential-process and a token in config should issue a warning. + let _server = registry::RegistryBuilder::new() + .http_api() + .http_index() + .alternative() + .no_configure_token() + .build(); + let p = project() + .file( + ".cargo/config", + r#" + [registries.alternative] + token = "alternative-sekrit" + credential-process = "false" + "#, + ) + .file( + "Cargo.toml", + r#" + [package] + name = "foo" + version = "0.1.0" + description = "foo" + authors = [] + license = "MIT" + homepage = "https://example.com/" + "#, + ) + .file("src/lib.rs", "") + .build(); + + p.cargo("publish --no-verify --registry alternative -Z credential-process") + .masquerade_as_nightly_cargo(&["credential-process"]) + .with_status(101) + .with_stderr( + "\ +[UPDATING] [..] +[ERROR] both `token` and `credential-process` were specified in the config for registry `alternative`. +Only one of these values may be set, remove one or the other to proceed. +", + ) + .run(); + + // Try with global credential-process, and registry-specific `token`. + // This should silently use the config token, and not run the "false" exe. + p.change_file( + ".cargo/config", + r#" + [registry] + credential-process = "false" + + [registries.alternative] + token = "alternative-sekrit" + "#, + ); + p.cargo("publish --no-verify --registry alternative -Z credential-process") + .masquerade_as_nightly_cargo(&["credential-process"]) + .with_stderr( + "\ +[UPDATING] [..] +[PACKAGING] foo v0.1.0 [..] +[PACKAGED] [..] +[UPLOADING] foo v0.1.0 [..] +[UPLOADED] foo v0.1.0 [..] +note: Waiting [..] +You may press ctrl-c [..] +[PUBLISHED] foo v0.1.0 [..] +", + ) + .run(); +} + +/// Setup for a test that will issue a command that needs to fetch a token. +/// +/// This does the following: +/// +/// * Spawn a thread that will act as an API server. +/// * Create a simple credential-process that will generate a fake token. +/// * Create a simple `foo` project to run the test against. +/// * Configure the credential-process config. +/// +/// Returns the simple `foo` project to test against and the API server handle. +fn get_token_test() -> (Project, TestRegistry) { + // API server that checks that the token is included correctly. + let server = registry::RegistryBuilder::new() + .no_configure_token() + .token(cargo_test_support::registry::Token::Plaintext( + "sekrit".to_string(), + )) + .alternative() + .http_api() + .build(); + // The credential process to use. + let cred_proj = project() + .at("cred_proj") + .file("Cargo.toml", &basic_manifest("test-cred", "1.0.0")) + .file( + "src/main.rs", + r#" + use std::fs::File; + use std::io::Write; + fn main() { + let mut f = File::options() + .write(true) + .create(true) + .append(true) + .open("runs.log") + .unwrap(); + write!(f, "+"); + println!("sekrit"); + } "#, + ) + .build(); + cred_proj.cargo("build").run(); + + let p = project() + .file( + ".cargo/config", + &format!( + r#" + [registries.alternative] + index = "{}" + credential-process = ["{}"] + "#, + server.index_url(), + toml_bin(&cred_proj, "test-cred") + ), + ) + .file( + "Cargo.toml", + r#" + [package] + name = "foo" + version = "0.1.0" + description = "foo" + authors = [] + license = "MIT" + homepage = "https://example.com/" + "#, + ) + .file("src/lib.rs", "") + .build(); + (p, server) +} + +#[cargo_test] +fn publish() { + // Checks that credential-process is used for `cargo publish`. + let (p, _t) = get_token_test(); + + p.cargo("publish --no-verify --registry alternative -Z credential-process") + .masquerade_as_nightly_cargo(&["credential-process"]) + .with_stderr( + "\ +[UPDATING] [..] +[PACKAGING] foo v0.1.0 [..] +[PACKAGED] [..] +[UPLOADING] foo v0.1.0 [..] +[UPLOADED] foo v0.1.0 [..] +note: Waiting [..] +You may press ctrl-c [..] +[PUBLISHED] foo v0.1.0 [..] +", + ) + .run(); + + let calls = read_to_string(p.root().join("runs.log")).unwrap().len(); + assert_eq!(calls, 1); +} + +#[cargo_test] +fn basic_unsupported() { + // Non-action commands don't support login/logout. + let registry = registry::RegistryBuilder::new() + .no_configure_token() + .build(); + cargo_util::paths::append( + &paths::home().join(".cargo/config"), + br#" + [registry] + credential-process = "false" + "#, + ) + .unwrap(); + + cargo_process("login -Z credential-process abcdefg") + .replace_crates_io(registry.index_url()) + .masquerade_as_nightly_cargo(&["credential-process"]) + .with_status(101) + .with_stderr( + "\ +[UPDATING] crates.io index +[ERROR] credential process `false` cannot be used to log in, \ +the credential-process configuration value must pass the \ +`{action}` argument in the config to support this command +", + ) + .run(); + + cargo_process("logout -Z credential-process") + .replace_crates_io(registry.index_url()) + .masquerade_as_nightly_cargo(&["credential-process"]) + .with_status(101) + .with_stderr( + "\ +[ERROR] credential process `false` cannot be used to log out, \ +the credential-process configuration value must pass the \ +`{action}` argument in the config to support this command +", + ) + .run(); +} + +#[cargo_test] +fn login() { + let server = registry::RegistryBuilder::new() + .no_configure_token() + .build(); + // The credential process to use. + let cred_proj = project() + .at("cred_proj") + .file("Cargo.toml", &basic_manifest("test-cred", "1.0.0")) + .file( + "src/main.rs", + r#" + use std::io::Read; + + fn main() {{ + assert_eq!(std::env::var("CARGO_REGISTRY_NAME_OPT").unwrap(), "crates-io"); + assert_eq!(std::env::var("CARGO_REGISTRY_INDEX_URL").unwrap(), "https://github.com/rust-lang/crates.io-index"); + assert_eq!(std::env::args().skip(1).next().unwrap(), "store"); + let mut buffer = String::new(); + std::io::stdin().read_to_string(&mut buffer).unwrap(); + assert_eq!(buffer, "abcdefg\n"); + std::fs::write("token-store", buffer).unwrap(); + }} + "#, + ) + .build(); + cred_proj.cargo("build").run(); + + cargo_util::paths::append( + &paths::home().join(".cargo/config"), + format!( + r#" + [registry] + credential-process = ["{}", "{{action}}"] + "#, + toml_bin(&cred_proj, "test-cred") + ) + .as_bytes(), + ) + .unwrap(); + + cargo_process("login -Z credential-process abcdefg") + .masquerade_as_nightly_cargo(&["credential-process"]) + .replace_crates_io(server.index_url()) + .with_stderr( + "\ +[UPDATING] [..] +[LOGIN] token for `crates.io` saved +", + ) + .run(); + assert_eq!( + fs::read_to_string(paths::root().join("token-store")).unwrap(), + "abcdefg\n" + ); +} + +#[cargo_test] +fn logout() { + let server = registry::RegistryBuilder::new() + .no_configure_token() + .build(); + // The credential process to use. + let cred_proj = project() + .at("cred_proj") + .file("Cargo.toml", &basic_manifest("test-cred", "1.0.0")) + .file( + "src/main.rs", + r#" + use std::io::Read; + + fn main() {{ + assert_eq!(std::env::var("CARGO_REGISTRY_NAME_OPT").unwrap(), "crates-io"); + assert_eq!(std::env::var("CARGO_REGISTRY_INDEX_URL").unwrap(), "https://github.com/rust-lang/crates.io-index"); + assert_eq!(std::env::args().skip(1).next().unwrap(), "erase"); + std::fs::write("token-store", "").unwrap(); + eprintln!("token for `crates-io` has been erased!") + }} + "#, + ) + .build(); + cred_proj.cargo("build").run(); + + cargo_util::paths::append( + &paths::home().join(".cargo/config"), + format!( + r#" + [registry] + credential-process = ["{}", "{{action}}"] + "#, + toml_bin(&cred_proj, "test-cred") + ) + .as_bytes(), + ) + .unwrap(); + + cargo_process("logout -Z credential-process") + .masquerade_as_nightly_cargo(&["credential-process"]) + .replace_crates_io(server.index_url()) + .with_stderr( + "\ +token for `crates-io` has been erased! +[LOGOUT] token for `crates-io` has been removed from local storage +[NOTE] This does not revoke the token on the registry server. + If you need to revoke the token, visit \ + and follow the instructions there. +", + ) + .run(); + assert_eq!( + fs::read_to_string(paths::root().join("token-store")).unwrap(), + "" + ); +} + +#[cargo_test] +fn yank() { + let (p, _t) = get_token_test(); + + p.cargo("yank --version 0.1.0 --registry alternative -Z credential-process") + .masquerade_as_nightly_cargo(&["credential-process"]) + .with_stderr( + "\ +[UPDATING] [..] +[YANK] foo@0.1.0 +", + ) + .run(); +} + +#[cargo_test] +fn owner() { + let (p, _t) = get_token_test(); + + p.cargo("owner --add username --registry alternative -Z credential-process") + .masquerade_as_nightly_cargo(&["credential-process"]) + .with_stderr( + "\ +[UPDATING] [..] +[OWNER] completed! +", + ) + .run(); +} + +#[cargo_test] +fn libexec_path() { + // cargo: prefixed names use the sysroot + let server = registry::RegistryBuilder::new() + .no_configure_token() + .build(); + cargo_util::paths::append( + &paths::home().join(".cargo/config"), + br#" + [registry] + credential-process = "cargo:doesnotexist" + "#, + ) + .unwrap(); + + cargo_process("login -Z credential-process abcdefg") + .masquerade_as_nightly_cargo(&["credential-process"]) + .replace_crates_io(server.index_url()) + .with_status(101) + .with_stderr( + // FIXME: Update "Caused by" error message once rust/pull/87704 is merged. + // On Windows, changing to a custom executable resolver has changed the + // error messages. + &format!("\ +[UPDATING] [..] +[ERROR] failed to execute `[..]libexec/cargo-credential-doesnotexist[EXE]` to store authentication token for registry `crates-io` + +Caused by: + [..] +"), + ) + .run(); +} + +#[cargo_test] +fn invalid_token_output() { + // Error when credential process does not output the expected format for a token. + let _server = registry::RegistryBuilder::new() + .alternative() + .no_configure_token() + .build(); + let cred_proj = project() + .at("cred_proj") + .file("Cargo.toml", &basic_manifest("test-cred", "1.0.0")) + .file("src/main.rs", r#"fn main() { print!("a\nb\n"); } "#) + .build(); + cred_proj.cargo("build").run(); + + cargo_util::paths::append( + &paths::home().join(".cargo/config"), + format!( + r#" + [registry] + credential-process = ["{}"] + "#, + toml_bin(&cred_proj, "test-cred") + ) + .as_bytes(), + ) + .unwrap(); + + let p = project() + .file("Cargo.toml", &basic_manifest("foo", "1.0.0")) + .file("src/lib.rs", "") + .build(); + + p.cargo("publish --no-verify --registry alternative -Z credential-process") + .masquerade_as_nightly_cargo(&["credential-process"]) + .with_status(101) + .with_stderr( + "\ +[UPDATING] [..] +[ERROR] credential process `[..]test-cred[EXE]` returned more than one line of output; expected a single token +", + ) + .run(); +} -- cgit v1.2.3