2023-01-14 22:48:53 +00:00
|
|
|
//! Network tests for SSH connections.
|
|
|
|
//!
|
|
|
|
//! Note that these tests will generally require setting CARGO_CONTAINER_TESTS
|
|
|
|
//! or CARGO_PUBLIC_NETWORK_TESTS.
|
|
|
|
//!
|
|
|
|
//! NOTE: The container tests almost certainly won't work on Windows.
|
|
|
|
|
|
|
|
use cargo_test_support::containers::{Container, ContainerHandle, MkFile};
|
2022-12-01 12:45:25 +00:00
|
|
|
use cargo_test_support::git::cargo_uses_gitoxide;
|
2023-01-14 22:48:53 +00:00
|
|
|
use cargo_test_support::{paths, process, project, Project};
|
|
|
|
use std::fs;
|
|
|
|
use std::io::Write;
|
|
|
|
use std::path::PathBuf;
|
|
|
|
|
|
|
|
fn ssh_repo_url(container: &ContainerHandle, name: &str) -> String {
|
|
|
|
let port = container.port_mappings[&22];
|
|
|
|
format!("ssh://testuser@127.0.0.1:{port}/repos/{name}.git")
|
|
|
|
}
|
|
|
|
|
|
|
|
/// The path to the client's private key.
|
|
|
|
fn key_path() -> PathBuf {
|
|
|
|
paths::home().join(".ssh/id_ed25519")
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Generates the SSH keys for authenticating into the container.
|
|
|
|
fn gen_ssh_keys() -> String {
|
|
|
|
let path = key_path();
|
|
|
|
process("ssh-keygen")
|
|
|
|
.args(&["-t", "ed25519", "-N", "", "-f"])
|
|
|
|
.arg(&path)
|
|
|
|
.exec_with_output()
|
|
|
|
.unwrap();
|
|
|
|
let pub_key = path.with_extension("pub");
|
|
|
|
fs::read_to_string(pub_key).unwrap()
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Handler for running ssh-agent for SSH authentication.
|
|
|
|
///
|
|
|
|
/// Be sure to set `SSH_AUTH_SOCK` when running a process in order to use the
|
|
|
|
/// agent. Keys will need to be copied into the container with the
|
|
|
|
/// `authorized_keys()` method.
|
|
|
|
struct Agent {
|
|
|
|
sock: PathBuf,
|
|
|
|
pid: String,
|
|
|
|
ssh_dir: PathBuf,
|
|
|
|
pub_key: String,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Agent {
|
|
|
|
fn launch() -> Agent {
|
|
|
|
let ssh_dir = paths::home().join(".ssh");
|
|
|
|
fs::create_dir(&ssh_dir).unwrap();
|
|
|
|
let pub_key = gen_ssh_keys();
|
|
|
|
|
|
|
|
let sock = paths::root().join("agent");
|
|
|
|
let output = process("ssh-agent")
|
|
|
|
.args(&["-s", "-a"])
|
|
|
|
.arg(&sock)
|
|
|
|
.exec_with_output()
|
|
|
|
.unwrap();
|
|
|
|
let stdout = std::str::from_utf8(&output.stdout).unwrap();
|
|
|
|
let start = stdout.find("SSH_AGENT_PID=").unwrap() + 14;
|
|
|
|
let end = &stdout[start..].find(';').unwrap();
|
|
|
|
let pid = (&stdout[start..start + end]).to_string();
|
|
|
|
eprintln!("SSH_AGENT_PID={pid}");
|
|
|
|
process("ssh-add")
|
|
|
|
.arg(key_path())
|
|
|
|
.env("SSH_AUTH_SOCK", &sock)
|
|
|
|
.exec_with_output()
|
|
|
|
.unwrap();
|
|
|
|
Agent {
|
|
|
|
sock,
|
|
|
|
pid,
|
|
|
|
ssh_dir,
|
|
|
|
pub_key,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Returns a `MkFile` which can be passed into the `Container` builder to
|
|
|
|
/// copy an `authorized_keys` file containing this agent's public key.
|
|
|
|
fn authorized_keys(&self) -> MkFile {
|
|
|
|
MkFile::path("home/testuser/.ssh/authorized_keys")
|
|
|
|
.contents(self.pub_key.as_bytes())
|
|
|
|
.mode(0o600)
|
|
|
|
.uid(100)
|
|
|
|
.gid(101)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Drop for Agent {
|
|
|
|
fn drop(&mut self) {
|
|
|
|
if let Err(e) = process("ssh-agent")
|
|
|
|
.args(&["-k", "-a"])
|
|
|
|
.arg(&self.sock)
|
|
|
|
.env("SSH_AGENT_PID", &self.pid)
|
|
|
|
.exec_with_output()
|
|
|
|
{
|
|
|
|
eprintln!("failed to stop ssh-agent: {e:?}");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Common project used for several tests.
|
|
|
|
fn foo_bar_project(url: &str) -> Project {
|
|
|
|
project()
|
|
|
|
.file(
|
|
|
|
"Cargo.toml",
|
|
|
|
&format!(
|
|
|
|
r#"
|
|
|
|
[package]
|
|
|
|
name = "foo"
|
|
|
|
version = "0.1.0"
|
|
|
|
|
|
|
|
[dependencies]
|
|
|
|
bar = {{ git = "{url}" }}
|
|
|
|
"#
|
|
|
|
),
|
|
|
|
)
|
|
|
|
.file("src/lib.rs", "")
|
|
|
|
.build()
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cargo_test(container_test)]
|
|
|
|
fn no_known_host() {
|
|
|
|
// When host is not known, it should show an error.
|
|
|
|
let sshd = Container::new("sshd").launch();
|
|
|
|
let url = ssh_repo_url(&sshd, "bar");
|
|
|
|
let p = foo_bar_project(&url);
|
|
|
|
p.cargo("fetch")
|
|
|
|
.with_status(101)
|
|
|
|
.with_stderr(
|
|
|
|
"\
|
|
|
|
[UPDATING] git repository `ssh://testuser@127.0.0.1:[..]/repos/bar.git`
|
|
|
|
error: failed to get `bar` as a dependency of package `foo v0.1.0 ([ROOT]/foo)`
|
|
|
|
|
|
|
|
Caused by:
|
|
|
|
failed to load source for dependency `bar`
|
|
|
|
|
|
|
|
Caused by:
|
|
|
|
Unable to update ssh://testuser@127.0.0.1:[..]/repos/bar.git
|
|
|
|
|
|
|
|
Caused by:
|
|
|
|
failed to clone into: [ROOT]/home/.cargo/git/db/bar-[..]
|
|
|
|
|
|
|
|
Caused by:
|
|
|
|
error: unknown SSH host key
|
|
|
|
The SSH host key for `[127.0.0.1]:[..]` is not known and cannot be validated.
|
|
|
|
|
|
|
|
To resolve this issue, add the host key to the `net.ssh.known-hosts` array in \
|
|
|
|
your Cargo configuration (such as [ROOT]/home/.cargo/config.toml) or in your \
|
|
|
|
OpenSSH known_hosts file at [ROOT]/home/.ssh/known_hosts
|
|
|
|
|
|
|
|
The key to add is:
|
|
|
|
|
|
|
|
[127.0.0.1]:[..] ecdsa-sha2-nistp256 AAAA[..]
|
|
|
|
|
|
|
|
The ECDSA key fingerprint is: SHA256:[..]
|
|
|
|
This fingerprint should be validated with the server administrator that it is correct.
|
|
|
|
|
|
|
|
See https://doc.rust-lang.org/stable/cargo/appendix/git-authentication.html#ssh-known-hosts \
|
|
|
|
for more information.
|
|
|
|
",
|
|
|
|
)
|
|
|
|
.run();
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cargo_test(container_test)]
|
|
|
|
fn known_host_works() {
|
|
|
|
// The key displayed in the error message should work when added to known_hosts.
|
|
|
|
let agent = Agent::launch();
|
|
|
|
let sshd = Container::new("sshd")
|
|
|
|
.file(agent.authorized_keys())
|
|
|
|
.launch();
|
|
|
|
let url = ssh_repo_url(&sshd, "bar");
|
|
|
|
let p = foo_bar_project(&url);
|
|
|
|
let output = p
|
|
|
|
.cargo("fetch")
|
|
|
|
.env("SSH_AUTH_SOCK", &agent.sock)
|
|
|
|
.build_command()
|
|
|
|
.output()
|
|
|
|
.unwrap();
|
|
|
|
let stderr = std::str::from_utf8(&output.stderr).unwrap();
|
|
|
|
|
|
|
|
// Validate the fingerprint while we're here.
|
|
|
|
let fingerprint = stderr
|
|
|
|
.lines()
|
2023-09-08 19:14:10 +00:00
|
|
|
.find_map(|line| line.strip_prefix(" The ECDSA key fingerprint is: "))
|
2023-01-14 22:48:53 +00:00
|
|
|
.unwrap()
|
|
|
|
.trim();
|
|
|
|
let finger_out = sshd.exec(&["ssh-keygen", "-l", "-f", "/etc/ssh/ssh_host_ecdsa_key.pub"]);
|
|
|
|
let gen_finger = std::str::from_utf8(&finger_out.stdout).unwrap();
|
|
|
|
// <key-size> <fingerprint> <comments…>
|
|
|
|
let gen_finger = gen_finger.split_whitespace().nth(1).unwrap();
|
|
|
|
assert_eq!(fingerprint, gen_finger);
|
|
|
|
|
|
|
|
// Add the key to known_hosts, and try again.
|
|
|
|
let key = stderr
|
|
|
|
.lines()
|
|
|
|
.find(|line| line.starts_with(" [127.0.0.1]:"))
|
|
|
|
.unwrap()
|
|
|
|
.trim();
|
|
|
|
fs::write(agent.ssh_dir.join("known_hosts"), key).unwrap();
|
|
|
|
p.cargo("fetch")
|
|
|
|
.env("SSH_AUTH_SOCK", &agent.sock)
|
|
|
|
.with_stderr("[UPDATING] git repository `ssh://testuser@127.0.0.1:[..]/repos/bar.git`")
|
|
|
|
.run();
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cargo_test(container_test)]
|
|
|
|
fn same_key_different_hostname() {
|
|
|
|
// The error message should mention if an identical key was found.
|
|
|
|
let agent = Agent::launch();
|
|
|
|
let sshd = Container::new("sshd").launch();
|
|
|
|
|
|
|
|
let hostkey = sshd.read_file("/etc/ssh/ssh_host_ecdsa_key.pub");
|
|
|
|
let known_hosts = format!("example.com {hostkey}");
|
|
|
|
fs::write(agent.ssh_dir.join("known_hosts"), known_hosts).unwrap();
|
|
|
|
|
|
|
|
let url = ssh_repo_url(&sshd, "bar");
|
|
|
|
let p = foo_bar_project(&url);
|
|
|
|
p.cargo("fetch")
|
|
|
|
.with_status(101)
|
|
|
|
.with_stderr(
|
|
|
|
"\
|
|
|
|
[UPDATING] git repository `ssh://testuser@127.0.0.1:[..]/repos/bar.git`
|
|
|
|
error: failed to get `bar` as a dependency of package `foo v0.1.0 ([ROOT]/foo)`
|
|
|
|
|
|
|
|
Caused by:
|
|
|
|
failed to load source for dependency `bar`
|
|
|
|
|
|
|
|
Caused by:
|
|
|
|
Unable to update ssh://testuser@127.0.0.1:[..]/repos/bar.git
|
|
|
|
|
|
|
|
Caused by:
|
|
|
|
failed to clone into: [ROOT]/home/.cargo/git/db/bar-[..]
|
|
|
|
|
|
|
|
Caused by:
|
|
|
|
error: unknown SSH host key
|
|
|
|
The SSH host key for `[127.0.0.1]:[..]` is not known and cannot be validated.
|
|
|
|
|
|
|
|
To resolve this issue, add the host key to the `net.ssh.known-hosts` array in \
|
|
|
|
your Cargo configuration (such as [ROOT]/home/.cargo/config.toml) or in your \
|
|
|
|
OpenSSH known_hosts file at [ROOT]/home/.ssh/known_hosts
|
|
|
|
|
|
|
|
The key to add is:
|
|
|
|
|
|
|
|
[127.0.0.1]:[..] ecdsa-sha2-nistp256 AAAA[..]
|
|
|
|
|
|
|
|
The ECDSA key fingerprint is: SHA256:[..]
|
|
|
|
This fingerprint should be validated with the server administrator that it is correct.
|
|
|
|
Note: This host key was found, but is associated with a different host:
|
|
|
|
[ROOT]/home/.ssh/known_hosts line 1: example.com
|
|
|
|
|
|
|
|
See https://doc.rust-lang.org/stable/cargo/appendix/git-authentication.html#ssh-known-hosts \
|
|
|
|
for more information.
|
|
|
|
",
|
|
|
|
)
|
|
|
|
.run();
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cargo_test(container_test)]
|
|
|
|
fn known_host_without_port() {
|
|
|
|
// A known_host entry without a port should match a connection to a non-standard port.
|
|
|
|
let agent = Agent::launch();
|
|
|
|
let sshd = Container::new("sshd")
|
|
|
|
.file(agent.authorized_keys())
|
|
|
|
.launch();
|
|
|
|
|
|
|
|
let hostkey = sshd.read_file("/etc/ssh/ssh_host_ecdsa_key.pub");
|
|
|
|
// The important part of this test is that this line does not have a port.
|
|
|
|
let known_hosts = format!("127.0.0.1 {hostkey}");
|
|
|
|
fs::write(agent.ssh_dir.join("known_hosts"), known_hosts).unwrap();
|
|
|
|
let url = ssh_repo_url(&sshd, "bar");
|
|
|
|
let p = foo_bar_project(&url);
|
|
|
|
p.cargo("fetch")
|
|
|
|
.env("SSH_AUTH_SOCK", &agent.sock)
|
|
|
|
.with_stderr("[UPDATING] git repository `ssh://testuser@127.0.0.1:[..]/repos/bar.git`")
|
|
|
|
.run();
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cargo_test(container_test)]
|
|
|
|
fn hostname_case_insensitive() {
|
|
|
|
// hostname checking should be case-insensitive.
|
|
|
|
let agent = Agent::launch();
|
|
|
|
let sshd = Container::new("sshd")
|
|
|
|
.file(agent.authorized_keys())
|
|
|
|
.launch();
|
|
|
|
|
|
|
|
// Consider using `gethostname-rs` instead?
|
|
|
|
let hostname = process("hostname").exec_with_output().unwrap();
|
|
|
|
let hostname = std::str::from_utf8(&hostname.stdout).unwrap().trim();
|
|
|
|
let inv_hostname = if hostname.chars().any(|c| c.is_lowercase()) {
|
|
|
|
hostname.to_uppercase()
|
|
|
|
} else {
|
|
|
|
// There should be *some* chars in the name.
|
|
|
|
assert!(hostname.chars().any(|c| c.is_uppercase()));
|
|
|
|
hostname.to_lowercase()
|
|
|
|
};
|
|
|
|
eprintln!("converted {hostname} to {inv_hostname}");
|
|
|
|
|
|
|
|
let hostkey = sshd.read_file("/etc/ssh/ssh_host_ecdsa_key.pub");
|
|
|
|
let known_hosts = format!("{inv_hostname} {hostkey}");
|
|
|
|
fs::write(agent.ssh_dir.join("known_hosts"), known_hosts).unwrap();
|
|
|
|
let port = sshd.port_mappings[&22];
|
|
|
|
let url = format!("ssh://testuser@{hostname}:{port}/repos/bar.git");
|
|
|
|
let p = foo_bar_project(&url);
|
|
|
|
p.cargo("fetch")
|
|
|
|
.env("SSH_AUTH_SOCK", &agent.sock)
|
|
|
|
.with_stderr(&format!(
|
|
|
|
"[UPDATING] git repository `ssh://testuser@{hostname}:{port}/repos/bar.git`"
|
|
|
|
))
|
|
|
|
.run();
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cargo_test(container_test)]
|
|
|
|
fn invalid_key_error() {
|
|
|
|
// An error when a known_host value doesn't match.
|
|
|
|
let agent = Agent::launch();
|
|
|
|
let sshd = Container::new("sshd")
|
|
|
|
.file(agent.authorized_keys())
|
|
|
|
.launch();
|
|
|
|
|
|
|
|
let port = sshd.port_mappings[&22];
|
|
|
|
let known_hosts = format!(
|
|
|
|
"[127.0.0.1]:{port} ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBLqLMclVr7MDuaVsm3sEnnq2OrGxTFiHSw90wd6N14BU8xVC9cZldC3rJ58Wmw6bEVKPjk7foNG0lHwS5bCKX+U=\n"
|
|
|
|
);
|
|
|
|
fs::write(agent.ssh_dir.join("known_hosts"), known_hosts).unwrap();
|
|
|
|
let url = ssh_repo_url(&sshd, "bar");
|
|
|
|
let p = foo_bar_project(&url);
|
|
|
|
p.cargo("fetch")
|
|
|
|
.env("SSH_AUTH_SOCK", &agent.sock)
|
|
|
|
.with_status(101)
|
|
|
|
.with_stderr(&format!("\
|
|
|
|
[UPDATING] git repository `ssh://testuser@127.0.0.1:{port}/repos/bar.git`
|
|
|
|
error: failed to get `bar` as a dependency of package `foo v0.1.0 ([ROOT]/foo)`
|
|
|
|
|
|
|
|
Caused by:
|
|
|
|
failed to load source for dependency `bar`
|
|
|
|
|
|
|
|
Caused by:
|
|
|
|
Unable to update ssh://testuser@127.0.0.1:{port}/repos/bar.git
|
|
|
|
|
|
|
|
Caused by:
|
|
|
|
failed to clone into: [ROOT]/home/.cargo/git/db/bar-[..]
|
|
|
|
|
|
|
|
Caused by:
|
|
|
|
error: SSH host key has changed for `[127.0.0.1]:{port}`
|
|
|
|
*********************************
|
|
|
|
* WARNING: HOST KEY HAS CHANGED *
|
|
|
|
*********************************
|
|
|
|
This may be caused by a man-in-the-middle attack, or the server may have changed its host key.
|
|
|
|
|
|
|
|
The ECDSA fingerprint for the key from the remote host is:
|
|
|
|
SHA256:[..]
|
|
|
|
|
|
|
|
You are strongly encouraged to contact the server administrator for `[127.0.0.1]:{port}` \
|
|
|
|
to verify that this new key is correct.
|
|
|
|
|
|
|
|
If you can verify that the server has a new key, you can resolve this error by \
|
|
|
|
removing the old ecdsa-sha2-nistp256 key for `[127.0.0.1]:{port}` located at \
|
|
|
|
[ROOT]/home/.ssh/known_hosts line 1, and adding the new key to the \
|
|
|
|
`net.ssh.known-hosts` array in your Cargo configuration (such as \
|
|
|
|
[ROOT]/home/.cargo/config.toml) or in your OpenSSH known_hosts file at \
|
|
|
|
[ROOT]/home/.ssh/known_hosts
|
|
|
|
|
|
|
|
The key provided by the remote host is:
|
|
|
|
|
|
|
|
[127.0.0.1]:{port} ecdsa-sha2-nistp256 [..]
|
|
|
|
|
|
|
|
See https://doc.rust-lang.org/stable/cargo/appendix/git-authentication.html#ssh-known-hosts for more information.
|
|
|
|
"))
|
|
|
|
.run();
|
|
|
|
// Add the key, it should work even with the old key left behind.
|
|
|
|
let hostkey = sshd.read_file("/etc/ssh/ssh_host_ecdsa_key.pub");
|
|
|
|
let known_hosts_path = agent.ssh_dir.join("known_hosts");
|
|
|
|
let mut f = fs::OpenOptions::new()
|
|
|
|
.append(true)
|
|
|
|
.open(known_hosts_path)
|
|
|
|
.unwrap();
|
|
|
|
write!(f, "[127.0.0.1]:{port} {hostkey}").unwrap();
|
|
|
|
drop(f);
|
|
|
|
p.cargo("fetch")
|
|
|
|
.env("SSH_AUTH_SOCK", &agent.sock)
|
|
|
|
.with_stderr("[UPDATING] git repository `ssh://testuser@127.0.0.1:[..]/repos/bar.git`")
|
|
|
|
.run();
|
|
|
|
}
|
|
|
|
|
2023-01-21 21:06:07 +00:00
|
|
|
// For unknown reasons, this test occasionally fails on Windows with a
|
|
|
|
// LIBSSH2_ERROR_KEY_EXCHANGE_FAILURE error:
|
|
|
|
// failed to start SSH session: Unable to exchange encryption keys; class=Ssh (23)
|
2023-01-22 20:23:51 +00:00
|
|
|
#[cargo_test(public_network_test, ignore_windows = "test is flaky on windows")]
|
2023-01-14 22:48:53 +00:00
|
|
|
fn invalid_github_key() {
|
|
|
|
// A key for github.com in known_hosts should override the built-in key.
|
|
|
|
// This uses a bogus key which should result in an error.
|
|
|
|
let ssh_dir = paths::home().join(".ssh");
|
|
|
|
fs::create_dir(&ssh_dir).unwrap();
|
|
|
|
let known_hosts = "\
|
|
|
|
github.com ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBLqLMclVr7MDuaVsm3sEnnq2OrGxTFiHSw90wd6N14BU8xVC9cZldC3rJ58Wmw6bEVKPjk7foNG0lHwS5bCKX+U=\n\
|
|
|
|
github.com ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDgi+8rMcyFCBq5y7BXrb2aaYGhMjlU3QDy7YDvtNL5KSecYOsaqQHaXr87Bbx0EEkgbhK4kVMkmThlCoNITQS9Vc3zIMQ+Tg6+O4qXx719uCzywl50Tb5tDqPGMj54jcq3VUiu/dvse0yeehyvzoPNWewgGWLx11KI4A4wOwMnc6guhculEWe9DjGEjUQ34lPbmdfu/Hza7ZVu/RhgF/wc43uzXWB2KpMEqtuY1SgRlCZqTASoEtfKZi0AuM7AEdOwE5aTotS4CQZHWimb1bMFpF4DAq92CZ8Jhrm4rWETbO29WmjviCJEA3KNQyd3oA7H9AE9z/22PJaVEmjiZZ+wyLgwyIpOlsnHYNEdGeQMQ4SgLRkARLwcnKmByv1AAxsBW4LI3Os4FpwxVPdXHcBebydtvxIsbtUVkkq99nbsIlnSRFSTvb0alrdzRuKTdWpHtN1v9hagFqmeCx/kJfH76NXYBbtaWZhSOnxfEbhLYuOb+IS4jYzHAIkzy9FjVuk=\n\
|
|
|
|
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIEeMB6BUAW6FfvfLxRO3kGASe0yXnrRT4kpqncsup2b2\n";
|
|
|
|
fs::write(ssh_dir.join("known_hosts"), known_hosts).unwrap();
|
|
|
|
let p = project()
|
|
|
|
.file(
|
|
|
|
"Cargo.toml",
|
|
|
|
r#"
|
|
|
|
[package]
|
|
|
|
name = "foo"
|
|
|
|
version = "0.1.0"
|
|
|
|
|
|
|
|
[dependencies]
|
|
|
|
bitflags = { git = "ssh://git@github.com/rust-lang/bitflags.git", tag = "1.3.2" }
|
|
|
|
"#,
|
|
|
|
)
|
|
|
|
.file("src/lib.rs", "")
|
|
|
|
.build();
|
|
|
|
p.cargo("fetch")
|
|
|
|
.with_status(101)
|
2022-12-01 12:45:25 +00:00
|
|
|
.with_stderr_contains(if cargo_uses_gitoxide() {
|
|
|
|
" git@github.com: Permission denied (publickey)."
|
|
|
|
} else {
|
|
|
|
" error: SSH host key has changed for `github.com`"
|
|
|
|
})
|
2023-01-14 22:48:53 +00:00
|
|
|
.run();
|
|
|
|
}
|
|
|
|
|
2023-01-21 21:06:07 +00:00
|
|
|
// For unknown reasons, this test occasionally fails on Windows with a
|
|
|
|
// LIBSSH2_ERROR_KEY_EXCHANGE_FAILURE error:
|
|
|
|
// failed to start SSH session: Unable to exchange encryption keys; class=Ssh (23)
|
2023-01-22 20:23:51 +00:00
|
|
|
#[cargo_test(public_network_test, ignore_windows = "test is flaky on windows")]
|
2023-01-14 22:48:53 +00:00
|
|
|
fn bundled_github_works() {
|
|
|
|
// The bundled key for github.com works.
|
|
|
|
//
|
|
|
|
// Use a bogus auth sock to force an authentication error.
|
|
|
|
// On Windows, if the agent service is running, it could allow a
|
|
|
|
// successful authentication.
|
|
|
|
//
|
|
|
|
// If the bundled hostkey did not work, it would result in an "unknown SSH
|
|
|
|
// host key" instead.
|
|
|
|
let bogus_auth_sock = paths::home().join("ssh_auth_sock");
|
|
|
|
let p = project()
|
|
|
|
.file(
|
|
|
|
"Cargo.toml",
|
|
|
|
r#"
|
|
|
|
[package]
|
|
|
|
name = "foo"
|
|
|
|
version = "0.1.0"
|
|
|
|
|
|
|
|
[dependencies]
|
|
|
|
bitflags = { git = "ssh://git@github.com/rust-lang/bitflags.git", tag = "1.3.2" }
|
|
|
|
"#,
|
|
|
|
)
|
|
|
|
.file("src/lib.rs", "")
|
|
|
|
.build();
|
2022-12-01 12:45:25 +00:00
|
|
|
let shared_stderr = "\
|
2023-01-14 22:48:53 +00:00
|
|
|
[UPDATING] git repository `ssh://git@github.com/rust-lang/bitflags.git`
|
|
|
|
error: failed to get `bitflags` as a dependency of package `foo v0.1.0 ([ROOT]/foo)`
|
|
|
|
|
|
|
|
Caused by:
|
|
|
|
failed to load source for dependency `bitflags`
|
|
|
|
|
|
|
|
Caused by:
|
|
|
|
Unable to update ssh://git@github.com/rust-lang/bitflags.git?tag=1.3.2
|
|
|
|
|
|
|
|
Caused by:
|
|
|
|
failed to clone into: [ROOT]/home/.cargo/git/db/bitflags-[..]
|
|
|
|
|
|
|
|
Caused by:
|
|
|
|
failed to authenticate when downloading repository
|
|
|
|
|
2022-12-01 12:45:25 +00:00
|
|
|
*";
|
|
|
|
let expected = if cargo_uses_gitoxide() {
|
|
|
|
format!(
|
|
|
|
"{shared_stderr} attempted to find username/password via `credential.helper`, but maybe the found credentials were incorrect
|
2023-01-14 22:48:53 +00:00
|
|
|
|
|
|
|
if the git CLI succeeds then `net.git-fetch-with-cli` may help here
|
|
|
|
https://doc.rust-lang.org/cargo/reference/config.html#netgit-fetch-with-cli
|
|
|
|
|
|
|
|
Caused by:
|
2022-12-01 12:45:25 +00:00
|
|
|
Credentials provided for \"ssh://git@github.com/rust-lang/bitflags.git\" were not accepted by the remote
|
|
|
|
|
|
|
|
Caused by:
|
|
|
|
git@github.com: Permission denied (publickey).
|
2023-01-14 22:48:53 +00:00
|
|
|
"
|
2022-12-01 12:45:25 +00:00
|
|
|
)
|
|
|
|
} else {
|
|
|
|
format!(
|
|
|
|
"{shared_stderr} attempted ssh-agent authentication, but no usernames succeeded: `git`
|
2023-01-14 22:48:53 +00:00
|
|
|
|
2022-12-01 12:45:25 +00:00
|
|
|
if the git CLI succeeds then `net.git-fetch-with-cli` may help here
|
|
|
|
https://doc.rust-lang.org/cargo/reference/config.html#netgit-fetch-with-cli
|
2023-01-14 22:48:53 +00:00
|
|
|
|
2022-12-01 12:45:25 +00:00
|
|
|
Caused by:
|
2023-04-02 22:32:48 +00:00
|
|
|
no authentication methods succeeded
|
2022-12-01 12:45:25 +00:00
|
|
|
"
|
|
|
|
)
|
|
|
|
};
|
2023-01-14 22:48:53 +00:00
|
|
|
p.cargo("fetch")
|
|
|
|
.env("SSH_AUTH_SOCK", &bogus_auth_sock)
|
|
|
|
.with_status(101)
|
2022-12-01 12:45:25 +00:00
|
|
|
.with_stderr(&expected)
|
|
|
|
.run();
|
|
|
|
|
|
|
|
let shared_stderr = "\
|
2023-01-14 22:48:53 +00:00
|
|
|
[UPDATING] git repository `ssh://git@github.com:22/rust-lang/bitflags.git`
|
|
|
|
error: failed to get `bitflags` as a dependency of package `foo v0.1.0 ([ROOT]/foo)`
|
|
|
|
|
|
|
|
Caused by:
|
|
|
|
failed to load source for dependency `bitflags`
|
|
|
|
|
|
|
|
Caused by:
|
|
|
|
Unable to update ssh://git@github.com:22/rust-lang/bitflags.git?tag=1.3.2
|
|
|
|
|
|
|
|
Caused by:
|
|
|
|
failed to clone into: [ROOT]/home/.cargo/git/db/bitflags-[..]
|
|
|
|
|
|
|
|
Caused by:
|
|
|
|
failed to authenticate when downloading repository
|
|
|
|
|
2022-12-01 12:45:25 +00:00
|
|
|
*";
|
|
|
|
|
|
|
|
let expected = if cargo_uses_gitoxide() {
|
|
|
|
format!(
|
|
|
|
"{shared_stderr} attempted to find username/password via `credential.helper`, but maybe the found credentials were incorrect
|
|
|
|
|
|
|
|
if the git CLI succeeds then `net.git-fetch-with-cli` may help here
|
|
|
|
https://doc.rust-lang.org/cargo/reference/config.html#netgit-fetch-with-cli
|
|
|
|
|
|
|
|
Caused by:
|
|
|
|
Credentials provided for \"ssh://git@github.com:22/rust-lang/bitflags.git\" were not accepted by the remote
|
|
|
|
|
|
|
|
Caused by:
|
|
|
|
git@github.com: Permission denied (publickey).
|
|
|
|
"
|
|
|
|
)
|
|
|
|
} else {
|
|
|
|
format!(
|
|
|
|
"{shared_stderr} attempted ssh-agent authentication, but no usernames succeeded: `git`
|
2023-01-14 22:48:53 +00:00
|
|
|
|
|
|
|
if the git CLI succeeds then `net.git-fetch-with-cli` may help here
|
|
|
|
https://doc.rust-lang.org/cargo/reference/config.html#netgit-fetch-with-cli
|
|
|
|
|
|
|
|
Caused by:
|
2023-04-02 22:32:48 +00:00
|
|
|
no authentication methods succeeded
|
2023-01-14 22:48:53 +00:00
|
|
|
"
|
2022-12-01 12:45:25 +00:00
|
|
|
)
|
|
|
|
};
|
|
|
|
|
|
|
|
// Explicit :22 should also work with bundled.
|
|
|
|
p.change_file(
|
|
|
|
"Cargo.toml",
|
|
|
|
r#"
|
|
|
|
[package]
|
|
|
|
name = "foo"
|
|
|
|
version = "0.1.0"
|
|
|
|
|
|
|
|
[dependencies]
|
|
|
|
bitflags = { git = "ssh://git@github.com:22/rust-lang/bitflags.git", tag = "1.3.2" }
|
|
|
|
"#,
|
|
|
|
);
|
|
|
|
p.cargo("fetch")
|
|
|
|
.env("SSH_AUTH_SOCK", &bogus_auth_sock)
|
|
|
|
.with_status(101)
|
|
|
|
.with_stderr(&expected)
|
2023-01-14 22:48:53 +00:00
|
|
|
.run();
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cargo_test(container_test)]
|
|
|
|
fn ssh_key_in_config() {
|
|
|
|
// known_host in config works.
|
|
|
|
let agent = Agent::launch();
|
|
|
|
let sshd = Container::new("sshd")
|
|
|
|
.file(agent.authorized_keys())
|
|
|
|
.launch();
|
|
|
|
let hostkey = sshd.read_file("/etc/ssh/ssh_host_ecdsa_key.pub");
|
|
|
|
let url = ssh_repo_url(&sshd, "bar");
|
|
|
|
let p = foo_bar_project(&url);
|
|
|
|
p.change_file(
|
|
|
|
".cargo/config.toml",
|
|
|
|
&format!(
|
|
|
|
r#"
|
|
|
|
[net.ssh]
|
|
|
|
known-hosts = ['127.0.0.1 {}']
|
|
|
|
"#,
|
|
|
|
hostkey.trim()
|
|
|
|
),
|
|
|
|
);
|
|
|
|
p.cargo("fetch")
|
|
|
|
.env("SSH_AUTH_SOCK", &agent.sock)
|
|
|
|
.with_stderr("[UPDATING] git repository `ssh://testuser@127.0.0.1:[..]/repos/bar.git`")
|
|
|
|
.run();
|
|
|
|
}
|