]>
Commit | Line | Data |
---|---|---|
0a29b90c FG |
1 | //! Network tests for SSH connections. |
2 | //! | |
3 | //! Note that these tests will generally require setting CARGO_CONTAINER_TESTS | |
4 | //! or CARGO_PUBLIC_NETWORK_TESTS. | |
5 | //! | |
6 | //! NOTE: The container tests almost certainly won't work on Windows. | |
7 | ||
8 | use cargo_test_support::containers::{Container, ContainerHandle, MkFile}; | |
9 | use cargo_test_support::git::cargo_uses_gitoxide; | |
10 | use cargo_test_support::{paths, process, project, Project}; | |
11 | use std::fs; | |
12 | use std::io::Write; | |
13 | use std::path::PathBuf; | |
14 | ||
15 | fn ssh_repo_url(container: &ContainerHandle, name: &str) -> String { | |
16 | let port = container.port_mappings[&22]; | |
17 | format!("ssh://testuser@127.0.0.1:{port}/repos/{name}.git") | |
18 | } | |
19 | ||
20 | /// The path to the client's private key. | |
21 | fn key_path() -> PathBuf { | |
22 | paths::home().join(".ssh/id_ed25519") | |
23 | } | |
24 | ||
25 | /// Generates the SSH keys for authenticating into the container. | |
26 | fn gen_ssh_keys() -> String { | |
27 | let path = key_path(); | |
28 | process("ssh-keygen") | |
29 | .args(&["-t", "ed25519", "-N", "", "-f"]) | |
30 | .arg(&path) | |
31 | .exec_with_output() | |
32 | .unwrap(); | |
33 | let pub_key = path.with_extension("pub"); | |
34 | fs::read_to_string(pub_key).unwrap() | |
35 | } | |
36 | ||
37 | /// Handler for running ssh-agent for SSH authentication. | |
38 | /// | |
39 | /// Be sure to set `SSH_AUTH_SOCK` when running a process in order to use the | |
40 | /// agent. Keys will need to be copied into the container with the | |
41 | /// `authorized_keys()` method. | |
42 | struct Agent { | |
43 | sock: PathBuf, | |
44 | pid: String, | |
45 | ssh_dir: PathBuf, | |
46 | pub_key: String, | |
47 | } | |
48 | ||
49 | impl Agent { | |
50 | fn launch() -> Agent { | |
51 | let ssh_dir = paths::home().join(".ssh"); | |
52 | fs::create_dir(&ssh_dir).unwrap(); | |
53 | let pub_key = gen_ssh_keys(); | |
54 | ||
55 | let sock = paths::root().join("agent"); | |
56 | let output = process("ssh-agent") | |
57 | .args(&["-s", "-a"]) | |
58 | .arg(&sock) | |
59 | .exec_with_output() | |
60 | .unwrap(); | |
61 | let stdout = std::str::from_utf8(&output.stdout).unwrap(); | |
62 | let start = stdout.find("SSH_AGENT_PID=").unwrap() + 14; | |
63 | let end = &stdout[start..].find(';').unwrap(); | |
64 | let pid = (&stdout[start..start + end]).to_string(); | |
65 | eprintln!("SSH_AGENT_PID={pid}"); | |
66 | process("ssh-add") | |
67 | .arg(key_path()) | |
68 | .env("SSH_AUTH_SOCK", &sock) | |
69 | .exec_with_output() | |
70 | .unwrap(); | |
71 | Agent { | |
72 | sock, | |
73 | pid, | |
74 | ssh_dir, | |
75 | pub_key, | |
76 | } | |
77 | } | |
78 | ||
79 | /// Returns a `MkFile` which can be passed into the `Container` builder to | |
80 | /// copy an `authorized_keys` file containing this agent's public key. | |
81 | fn authorized_keys(&self) -> MkFile { | |
82 | MkFile::path("home/testuser/.ssh/authorized_keys") | |
83 | .contents(self.pub_key.as_bytes()) | |
84 | .mode(0o600) | |
85 | .uid(100) | |
86 | .gid(101) | |
87 | } | |
88 | } | |
89 | ||
90 | impl Drop for Agent { | |
91 | fn drop(&mut self) { | |
92 | if let Err(e) = process("ssh-agent") | |
93 | .args(&["-k", "-a"]) | |
94 | .arg(&self.sock) | |
95 | .env("SSH_AGENT_PID", &self.pid) | |
96 | .exec_with_output() | |
97 | { | |
98 | eprintln!("failed to stop ssh-agent: {e:?}"); | |
99 | } | |
100 | } | |
101 | } | |
102 | ||
103 | /// Common project used for several tests. | |
104 | fn foo_bar_project(url: &str) -> Project { | |
105 | project() | |
106 | .file( | |
107 | "Cargo.toml", | |
108 | &format!( | |
109 | r#" | |
110 | [package] | |
111 | name = "foo" | |
112 | version = "0.1.0" | |
113 | ||
114 | [dependencies] | |
115 | bar = {{ git = "{url}" }} | |
116 | "# | |
117 | ), | |
118 | ) | |
119 | .file("src/lib.rs", "") | |
120 | .build() | |
121 | } | |
122 | ||
123 | #[cargo_test(container_test)] | |
124 | fn no_known_host() { | |
125 | // When host is not known, it should show an error. | |
126 | let sshd = Container::new("sshd").launch(); | |
127 | let url = ssh_repo_url(&sshd, "bar"); | |
128 | let p = foo_bar_project(&url); | |
129 | p.cargo("fetch") | |
130 | .with_status(101) | |
131 | .with_stderr( | |
132 | "\ | |
133 | [UPDATING] git repository `ssh://testuser@127.0.0.1:[..]/repos/bar.git` | |
134 | error: failed to get `bar` as a dependency of package `foo v0.1.0 ([ROOT]/foo)` | |
135 | ||
136 | Caused by: | |
137 | failed to load source for dependency `bar` | |
138 | ||
139 | Caused by: | |
140 | Unable to update ssh://testuser@127.0.0.1:[..]/repos/bar.git | |
141 | ||
142 | Caused by: | |
143 | failed to clone into: [ROOT]/home/.cargo/git/db/bar-[..] | |
144 | ||
145 | Caused by: | |
146 | error: unknown SSH host key | |
147 | The SSH host key for `[127.0.0.1]:[..]` is not known and cannot be validated. | |
148 | ||
149 | To resolve this issue, add the host key to the `net.ssh.known-hosts` array in \ | |
150 | your Cargo configuration (such as [ROOT]/home/.cargo/config.toml) or in your \ | |
151 | OpenSSH known_hosts file at [ROOT]/home/.ssh/known_hosts | |
152 | ||
153 | The key to add is: | |
154 | ||
155 | [127.0.0.1]:[..] ecdsa-sha2-nistp256 AAAA[..] | |
156 | ||
157 | The ECDSA key fingerprint is: SHA256:[..] | |
158 | This fingerprint should be validated with the server administrator that it is correct. | |
159 | ||
160 | See https://doc.rust-lang.org/stable/cargo/appendix/git-authentication.html#ssh-known-hosts \ | |
161 | for more information. | |
162 | ", | |
163 | ) | |
164 | .run(); | |
165 | } | |
166 | ||
167 | #[cargo_test(container_test)] | |
168 | fn known_host_works() { | |
169 | // The key displayed in the error message should work when added to known_hosts. | |
170 | let agent = Agent::launch(); | |
171 | let sshd = Container::new("sshd") | |
172 | .file(agent.authorized_keys()) | |
173 | .launch(); | |
174 | let url = ssh_repo_url(&sshd, "bar"); | |
175 | let p = foo_bar_project(&url); | |
176 | let output = p | |
177 | .cargo("fetch") | |
178 | .env("SSH_AUTH_SOCK", &agent.sock) | |
179 | .build_command() | |
180 | .output() | |
181 | .unwrap(); | |
182 | let stderr = std::str::from_utf8(&output.stderr).unwrap(); | |
183 | ||
184 | // Validate the fingerprint while we're here. | |
185 | let fingerprint = stderr | |
186 | .lines() | |
781aab86 | 187 | .find_map(|line| line.strip_prefix(" The ECDSA key fingerprint is: ")) |
0a29b90c FG |
188 | .unwrap() |
189 | .trim(); | |
0a29b90c FG |
190 | let finger_out = sshd.exec(&["ssh-keygen", "-l", "-f", "/etc/ssh/ssh_host_ecdsa_key.pub"]); |
191 | let gen_finger = std::str::from_utf8(&finger_out.stdout).unwrap(); | |
192 | // <key-size> <fingerprint> <comments…> | |
193 | let gen_finger = gen_finger.split_whitespace().nth(1).unwrap(); | |
194 | assert_eq!(fingerprint, gen_finger); | |
195 | ||
196 | // Add the key to known_hosts, and try again. | |
197 | let key = stderr | |
198 | .lines() | |
199 | .find(|line| line.starts_with(" [127.0.0.1]:")) | |
200 | .unwrap() | |
201 | .trim(); | |
202 | fs::write(agent.ssh_dir.join("known_hosts"), key).unwrap(); | |
203 | p.cargo("fetch") | |
204 | .env("SSH_AUTH_SOCK", &agent.sock) | |
205 | .with_stderr("[UPDATING] git repository `ssh://testuser@127.0.0.1:[..]/repos/bar.git`") | |
206 | .run(); | |
207 | } | |
208 | ||
209 | #[cargo_test(container_test)] | |
210 | fn same_key_different_hostname() { | |
211 | // The error message should mention if an identical key was found. | |
212 | let agent = Agent::launch(); | |
213 | let sshd = Container::new("sshd").launch(); | |
214 | ||
215 | let hostkey = sshd.read_file("/etc/ssh/ssh_host_ecdsa_key.pub"); | |
216 | let known_hosts = format!("example.com {hostkey}"); | |
217 | fs::write(agent.ssh_dir.join("known_hosts"), known_hosts).unwrap(); | |
218 | ||
219 | let url = ssh_repo_url(&sshd, "bar"); | |
220 | let p = foo_bar_project(&url); | |
221 | p.cargo("fetch") | |
222 | .with_status(101) | |
223 | .with_stderr( | |
224 | "\ | |
225 | [UPDATING] git repository `ssh://testuser@127.0.0.1:[..]/repos/bar.git` | |
226 | error: failed to get `bar` as a dependency of package `foo v0.1.0 ([ROOT]/foo)` | |
227 | ||
228 | Caused by: | |
229 | failed to load source for dependency `bar` | |
230 | ||
231 | Caused by: | |
232 | Unable to update ssh://testuser@127.0.0.1:[..]/repos/bar.git | |
233 | ||
234 | Caused by: | |
235 | failed to clone into: [ROOT]/home/.cargo/git/db/bar-[..] | |
236 | ||
237 | Caused by: | |
238 | error: unknown SSH host key | |
239 | The SSH host key for `[127.0.0.1]:[..]` is not known and cannot be validated. | |
240 | ||
241 | To resolve this issue, add the host key to the `net.ssh.known-hosts` array in \ | |
242 | your Cargo configuration (such as [ROOT]/home/.cargo/config.toml) or in your \ | |
243 | OpenSSH known_hosts file at [ROOT]/home/.ssh/known_hosts | |
244 | ||
245 | The key to add is: | |
246 | ||
247 | [127.0.0.1]:[..] ecdsa-sha2-nistp256 AAAA[..] | |
248 | ||
249 | The ECDSA key fingerprint is: SHA256:[..] | |
250 | This fingerprint should be validated with the server administrator that it is correct. | |
251 | Note: This host key was found, but is associated with a different host: | |
252 | [ROOT]/home/.ssh/known_hosts line 1: example.com | |
253 | ||
254 | See https://doc.rust-lang.org/stable/cargo/appendix/git-authentication.html#ssh-known-hosts \ | |
255 | for more information. | |
256 | ", | |
257 | ) | |
258 | .run(); | |
259 | } | |
260 | ||
261 | #[cargo_test(container_test)] | |
262 | fn known_host_without_port() { | |
263 | // A known_host entry without a port should match a connection to a non-standard port. | |
264 | let agent = Agent::launch(); | |
265 | let sshd = Container::new("sshd") | |
266 | .file(agent.authorized_keys()) | |
267 | .launch(); | |
268 | ||
269 | let hostkey = sshd.read_file("/etc/ssh/ssh_host_ecdsa_key.pub"); | |
270 | // The important part of this test is that this line does not have a port. | |
271 | let known_hosts = format!("127.0.0.1 {hostkey}"); | |
272 | fs::write(agent.ssh_dir.join("known_hosts"), known_hosts).unwrap(); | |
273 | let url = ssh_repo_url(&sshd, "bar"); | |
274 | let p = foo_bar_project(&url); | |
275 | p.cargo("fetch") | |
276 | .env("SSH_AUTH_SOCK", &agent.sock) | |
277 | .with_stderr("[UPDATING] git repository `ssh://testuser@127.0.0.1:[..]/repos/bar.git`") | |
278 | .run(); | |
279 | } | |
280 | ||
281 | #[cargo_test(container_test)] | |
282 | fn hostname_case_insensitive() { | |
283 | // hostname checking should be case-insensitive. | |
284 | let agent = Agent::launch(); | |
285 | let sshd = Container::new("sshd") | |
286 | .file(agent.authorized_keys()) | |
287 | .launch(); | |
288 | ||
289 | // Consider using `gethostname-rs` instead? | |
290 | let hostname = process("hostname").exec_with_output().unwrap(); | |
291 | let hostname = std::str::from_utf8(&hostname.stdout).unwrap().trim(); | |
292 | let inv_hostname = if hostname.chars().any(|c| c.is_lowercase()) { | |
293 | hostname.to_uppercase() | |
294 | } else { | |
295 | // There should be *some* chars in the name. | |
296 | assert!(hostname.chars().any(|c| c.is_uppercase())); | |
297 | hostname.to_lowercase() | |
298 | }; | |
299 | eprintln!("converted {hostname} to {inv_hostname}"); | |
300 | ||
301 | let hostkey = sshd.read_file("/etc/ssh/ssh_host_ecdsa_key.pub"); | |
302 | let known_hosts = format!("{inv_hostname} {hostkey}"); | |
303 | fs::write(agent.ssh_dir.join("known_hosts"), known_hosts).unwrap(); | |
304 | let port = sshd.port_mappings[&22]; | |
305 | let url = format!("ssh://testuser@{hostname}:{port}/repos/bar.git"); | |
306 | let p = foo_bar_project(&url); | |
307 | p.cargo("fetch") | |
308 | .env("SSH_AUTH_SOCK", &agent.sock) | |
309 | .with_stderr(&format!( | |
310 | "[UPDATING] git repository `ssh://testuser@{hostname}:{port}/repos/bar.git`" | |
311 | )) | |
312 | .run(); | |
313 | } | |
314 | ||
315 | #[cargo_test(container_test)] | |
316 | fn invalid_key_error() { | |
317 | // An error when a known_host value doesn't match. | |
318 | let agent = Agent::launch(); | |
319 | let sshd = Container::new("sshd") | |
320 | .file(agent.authorized_keys()) | |
321 | .launch(); | |
322 | ||
323 | let port = sshd.port_mappings[&22]; | |
324 | let known_hosts = format!( | |
325 | "[127.0.0.1]:{port} ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBLqLMclVr7MDuaVsm3sEnnq2OrGxTFiHSw90wd6N14BU8xVC9cZldC3rJ58Wmw6bEVKPjk7foNG0lHwS5bCKX+U=\n" | |
326 | ); | |
327 | fs::write(agent.ssh_dir.join("known_hosts"), known_hosts).unwrap(); | |
328 | let url = ssh_repo_url(&sshd, "bar"); | |
329 | let p = foo_bar_project(&url); | |
330 | p.cargo("fetch") | |
331 | .env("SSH_AUTH_SOCK", &agent.sock) | |
332 | .with_status(101) | |
333 | .with_stderr(&format!("\ | |
334 | [UPDATING] git repository `ssh://testuser@127.0.0.1:{port}/repos/bar.git` | |
335 | error: failed to get `bar` as a dependency of package `foo v0.1.0 ([ROOT]/foo)` | |
336 | ||
337 | Caused by: | |
338 | failed to load source for dependency `bar` | |
339 | ||
340 | Caused by: | |
341 | Unable to update ssh://testuser@127.0.0.1:{port}/repos/bar.git | |
342 | ||
343 | Caused by: | |
344 | failed to clone into: [ROOT]/home/.cargo/git/db/bar-[..] | |
345 | ||
346 | Caused by: | |
347 | error: SSH host key has changed for `[127.0.0.1]:{port}` | |
348 | ********************************* | |
349 | * WARNING: HOST KEY HAS CHANGED * | |
350 | ********************************* | |
351 | This may be caused by a man-in-the-middle attack, or the server may have changed its host key. | |
352 | ||
353 | The ECDSA fingerprint for the key from the remote host is: | |
354 | SHA256:[..] | |
355 | ||
356 | You are strongly encouraged to contact the server administrator for `[127.0.0.1]:{port}` \ | |
357 | to verify that this new key is correct. | |
358 | ||
359 | If you can verify that the server has a new key, you can resolve this error by \ | |
360 | removing the old ecdsa-sha2-nistp256 key for `[127.0.0.1]:{port}` located at \ | |
361 | [ROOT]/home/.ssh/known_hosts line 1, and adding the new key to the \ | |
362 | `net.ssh.known-hosts` array in your Cargo configuration (such as \ | |
363 | [ROOT]/home/.cargo/config.toml) or in your OpenSSH known_hosts file at \ | |
364 | [ROOT]/home/.ssh/known_hosts | |
365 | ||
366 | The key provided by the remote host is: | |
367 | ||
368 | [127.0.0.1]:{port} ecdsa-sha2-nistp256 [..] | |
369 | ||
370 | See https://doc.rust-lang.org/stable/cargo/appendix/git-authentication.html#ssh-known-hosts for more information. | |
371 | ")) | |
372 | .run(); | |
373 | // Add the key, it should work even with the old key left behind. | |
374 | let hostkey = sshd.read_file("/etc/ssh/ssh_host_ecdsa_key.pub"); | |
375 | let known_hosts_path = agent.ssh_dir.join("known_hosts"); | |
376 | let mut f = fs::OpenOptions::new() | |
377 | .append(true) | |
378 | .open(known_hosts_path) | |
379 | .unwrap(); | |
380 | write!(f, "[127.0.0.1]:{port} {hostkey}").unwrap(); | |
381 | drop(f); | |
382 | p.cargo("fetch") | |
383 | .env("SSH_AUTH_SOCK", &agent.sock) | |
384 | .with_stderr("[UPDATING] git repository `ssh://testuser@127.0.0.1:[..]/repos/bar.git`") | |
385 | .run(); | |
386 | } | |
387 | ||
388 | // For unknown reasons, this test occasionally fails on Windows with a | |
389 | // LIBSSH2_ERROR_KEY_EXCHANGE_FAILURE error: | |
390 | // failed to start SSH session: Unable to exchange encryption keys; class=Ssh (23) | |
391 | #[cargo_test(public_network_test, ignore_windows = "test is flaky on windows")] | |
392 | fn invalid_github_key() { | |
393 | // A key for github.com in known_hosts should override the built-in key. | |
394 | // This uses a bogus key which should result in an error. | |
395 | let ssh_dir = paths::home().join(".ssh"); | |
396 | fs::create_dir(&ssh_dir).unwrap(); | |
397 | let known_hosts = "\ | |
398 | github.com ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBLqLMclVr7MDuaVsm3sEnnq2OrGxTFiHSw90wd6N14BU8xVC9cZldC3rJ58Wmw6bEVKPjk7foNG0lHwS5bCKX+U=\n\ | |
399 | github.com ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDgi+8rMcyFCBq5y7BXrb2aaYGhMjlU3QDy7YDvtNL5KSecYOsaqQHaXr87Bbx0EEkgbhK4kVMkmThlCoNITQS9Vc3zIMQ+Tg6+O4qXx719uCzywl50Tb5tDqPGMj54jcq3VUiu/dvse0yeehyvzoPNWewgGWLx11KI4A4wOwMnc6guhculEWe9DjGEjUQ34lPbmdfu/Hza7ZVu/RhgF/wc43uzXWB2KpMEqtuY1SgRlCZqTASoEtfKZi0AuM7AEdOwE5aTotS4CQZHWimb1bMFpF4DAq92CZ8Jhrm4rWETbO29WmjviCJEA3KNQyd3oA7H9AE9z/22PJaVEmjiZZ+wyLgwyIpOlsnHYNEdGeQMQ4SgLRkARLwcnKmByv1AAxsBW4LI3Os4FpwxVPdXHcBebydtvxIsbtUVkkq99nbsIlnSRFSTvb0alrdzRuKTdWpHtN1v9hagFqmeCx/kJfH76NXYBbtaWZhSOnxfEbhLYuOb+IS4jYzHAIkzy9FjVuk=\n\ | |
400 | ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIEeMB6BUAW6FfvfLxRO3kGASe0yXnrRT4kpqncsup2b2\n"; | |
401 | fs::write(ssh_dir.join("known_hosts"), known_hosts).unwrap(); | |
402 | let p = project() | |
403 | .file( | |
404 | "Cargo.toml", | |
405 | r#" | |
406 | [package] | |
407 | name = "foo" | |
408 | version = "0.1.0" | |
409 | ||
410 | [dependencies] | |
411 | bitflags = { git = "ssh://git@github.com/rust-lang/bitflags.git", tag = "1.3.2" } | |
412 | "#, | |
413 | ) | |
414 | .file("src/lib.rs", "") | |
415 | .build(); | |
416 | p.cargo("fetch") | |
417 | .with_status(101) | |
418 | .with_stderr_contains(if cargo_uses_gitoxide() { | |
419 | " git@github.com: Permission denied (publickey)." | |
420 | } else { | |
421 | " error: SSH host key has changed for `github.com`" | |
422 | }) | |
423 | .run(); | |
424 | } | |
425 | ||
426 | // For unknown reasons, this test occasionally fails on Windows with a | |
427 | // LIBSSH2_ERROR_KEY_EXCHANGE_FAILURE error: | |
428 | // failed to start SSH session: Unable to exchange encryption keys; class=Ssh (23) | |
429 | #[cargo_test(public_network_test, ignore_windows = "test is flaky on windows")] | |
430 | fn bundled_github_works() { | |
431 | // The bundled key for github.com works. | |
432 | // | |
433 | // Use a bogus auth sock to force an authentication error. | |
434 | // On Windows, if the agent service is running, it could allow a | |
435 | // successful authentication. | |
436 | // | |
437 | // If the bundled hostkey did not work, it would result in an "unknown SSH | |
438 | // host key" instead. | |
439 | let bogus_auth_sock = paths::home().join("ssh_auth_sock"); | |
440 | let p = project() | |
441 | .file( | |
442 | "Cargo.toml", | |
443 | r#" | |
444 | [package] | |
445 | name = "foo" | |
446 | version = "0.1.0" | |
447 | ||
448 | [dependencies] | |
449 | bitflags = { git = "ssh://git@github.com/rust-lang/bitflags.git", tag = "1.3.2" } | |
450 | "#, | |
451 | ) | |
452 | .file("src/lib.rs", "") | |
453 | .build(); | |
454 | let shared_stderr = "\ | |
455 | [UPDATING] git repository `ssh://git@github.com/rust-lang/bitflags.git` | |
456 | error: failed to get `bitflags` as a dependency of package `foo v0.1.0 ([ROOT]/foo)` | |
457 | ||
458 | Caused by: | |
459 | failed to load source for dependency `bitflags` | |
460 | ||
461 | Caused by: | |
462 | Unable to update ssh://git@github.com/rust-lang/bitflags.git?tag=1.3.2 | |
463 | ||
464 | Caused by: | |
465 | failed to clone into: [ROOT]/home/.cargo/git/db/bitflags-[..] | |
466 | ||
467 | Caused by: | |
468 | failed to authenticate when downloading repository | |
469 | ||
470 | *"; | |
471 | let expected = if cargo_uses_gitoxide() { | |
472 | format!( | |
473 | "{shared_stderr} attempted to find username/password via `credential.helper`, but maybe the found credentials were incorrect | |
474 | ||
475 | if the git CLI succeeds then `net.git-fetch-with-cli` may help here | |
476 | https://doc.rust-lang.org/cargo/reference/config.html#netgit-fetch-with-cli | |
477 | ||
478 | Caused by: | |
479 | Credentials provided for \"ssh://git@github.com/rust-lang/bitflags.git\" were not accepted by the remote | |
480 | ||
481 | Caused by: | |
482 | git@github.com: Permission denied (publickey). | |
483 | " | |
484 | ) | |
485 | } else { | |
486 | format!( | |
487 | "{shared_stderr} attempted ssh-agent authentication, but no usernames succeeded: `git` | |
488 | ||
489 | if the git CLI succeeds then `net.git-fetch-with-cli` may help here | |
490 | https://doc.rust-lang.org/cargo/reference/config.html#netgit-fetch-with-cli | |
491 | ||
492 | Caused by: | |
493 | no authentication methods succeeded | |
494 | " | |
495 | ) | |
496 | }; | |
497 | p.cargo("fetch") | |
498 | .env("SSH_AUTH_SOCK", &bogus_auth_sock) | |
499 | .with_status(101) | |
500 | .with_stderr(&expected) | |
501 | .run(); | |
502 | ||
503 | let shared_stderr = "\ | |
504 | [UPDATING] git repository `ssh://git@github.com:22/rust-lang/bitflags.git` | |
505 | error: failed to get `bitflags` as a dependency of package `foo v0.1.0 ([ROOT]/foo)` | |
506 | ||
507 | Caused by: | |
508 | failed to load source for dependency `bitflags` | |
509 | ||
510 | Caused by: | |
511 | Unable to update ssh://git@github.com:22/rust-lang/bitflags.git?tag=1.3.2 | |
512 | ||
513 | Caused by: | |
514 | failed to clone into: [ROOT]/home/.cargo/git/db/bitflags-[..] | |
515 | ||
516 | Caused by: | |
517 | failed to authenticate when downloading repository | |
518 | ||
519 | *"; | |
520 | ||
521 | let expected = if cargo_uses_gitoxide() { | |
522 | format!( | |
523 | "{shared_stderr} attempted to find username/password via `credential.helper`, but maybe the found credentials were incorrect | |
524 | ||
525 | if the git CLI succeeds then `net.git-fetch-with-cli` may help here | |
526 | https://doc.rust-lang.org/cargo/reference/config.html#netgit-fetch-with-cli | |
527 | ||
528 | Caused by: | |
529 | Credentials provided for \"ssh://git@github.com:22/rust-lang/bitflags.git\" were not accepted by the remote | |
530 | ||
531 | Caused by: | |
532 | git@github.com: Permission denied (publickey). | |
533 | " | |
534 | ) | |
535 | } else { | |
536 | format!( | |
537 | "{shared_stderr} attempted ssh-agent authentication, but no usernames succeeded: `git` | |
538 | ||
539 | if the git CLI succeeds then `net.git-fetch-with-cli` may help here | |
540 | https://doc.rust-lang.org/cargo/reference/config.html#netgit-fetch-with-cli | |
541 | ||
542 | Caused by: | |
543 | no authentication methods succeeded | |
544 | " | |
545 | ) | |
546 | }; | |
547 | ||
548 | // Explicit :22 should also work with bundled. | |
549 | p.change_file( | |
550 | "Cargo.toml", | |
551 | r#" | |
552 | [package] | |
553 | name = "foo" | |
554 | version = "0.1.0" | |
555 | ||
556 | [dependencies] | |
557 | bitflags = { git = "ssh://git@github.com:22/rust-lang/bitflags.git", tag = "1.3.2" } | |
558 | "#, | |
559 | ); | |
560 | p.cargo("fetch") | |
561 | .env("SSH_AUTH_SOCK", &bogus_auth_sock) | |
562 | .with_status(101) | |
563 | .with_stderr(&expected) | |
564 | .run(); | |
565 | } | |
566 | ||
567 | #[cargo_test(container_test)] | |
568 | fn ssh_key_in_config() { | |
569 | // known_host in config works. | |
570 | let agent = Agent::launch(); | |
571 | let sshd = Container::new("sshd") | |
572 | .file(agent.authorized_keys()) | |
573 | .launch(); | |
574 | let hostkey = sshd.read_file("/etc/ssh/ssh_host_ecdsa_key.pub"); | |
575 | let url = ssh_repo_url(&sshd, "bar"); | |
576 | let p = foo_bar_project(&url); | |
577 | p.change_file( | |
578 | ".cargo/config.toml", | |
579 | &format!( | |
580 | r#" | |
581 | [net.ssh] | |
582 | known-hosts = ['127.0.0.1 {}'] | |
583 | "#, | |
584 | hostkey.trim() | |
585 | ), | |
586 | ); | |
587 | p.cargo("fetch") | |
588 | .env("SSH_AUTH_SOCK", &agent.sock) | |
589 | .with_stderr("[UPDATING] git repository `ssh://testuser@127.0.0.1:[..]/repos/bar.git`") | |
590 | .run(); | |
591 | } |