|
1 |
+ |
//! A console verb run without a terminal says so instead of panicking.
|
|
2 |
+ |
//!
|
|
3 |
+ |
//! This is not a hypothetical. The installer's sshd drop-in
|
|
4 |
+ |
//! (`etc/ssh/sshd_config.d/20-alloy-installer.conf`) runs `alloy install` as a
|
|
5 |
+ |
//! `ForceCommand`, so the first thing a stranger's ssh client does to a headless
|
|
6 |
+ |
//! machine reaches the shell's terminal setup. Without `-t` there is no pty, and
|
|
7 |
+ |
//! `ratatui::init` panics: the session got a Rust backtrace naming a crate
|
|
8 |
+ |
//! version and a line number in a dependency. Observed 2026-08-09 against a
|
|
9 |
+ |
//! booted ISO, which is also the only way it could have been observed — every
|
|
10 |
+ |
//! interactive use has a terminal by definition.
|
|
11 |
+ |
//!
|
|
12 |
+ |
//! Spawned rather than called, because having no terminal is a property of the
|
|
13 |
+ |
//! process and not of an argument. `Command::output` pipes stdout, so the child
|
|
14 |
+ |
//! is in exactly the state the ssh session was.
|
|
15 |
+ |
|
|
16 |
+ |
use std::process::Command;
|
|
17 |
+ |
|
|
18 |
+ |
#[test]
|
|
19 |
+ |
fn a_verb_without_a_terminal_explains_itself_and_fails() {
|
|
20 |
+ |
let output = Command::new(env!("CARGO_BIN_EXE_alloy"))
|
|
21 |
+ |
.arg("net")
|
|
22 |
+ |
.output()
|
|
23 |
+ |
.expect("running the console");
|
|
24 |
+ |
|
|
25 |
+ |
assert!(
|
|
26 |
+ |
!output.status.success(),
|
|
27 |
+ |
"a console with nowhere to draw exited 0",
|
|
28 |
+ |
);
|
|
29 |
+ |
|
|
30 |
+ |
let stderr = String::from_utf8_lossy(&output.stderr);
|
|
31 |
+ |
assert!(
|
|
32 |
+ |
stderr.contains("needs a terminal"),
|
|
33 |
+ |
"the message does not say what is wrong:\n{stderr}",
|
|
34 |
+ |
);
|
|
35 |
+ |
// The remedy, not just the diagnosis: whoever hits this is at an ssh
|
|
36 |
+ |
// prompt and the fix is one flag.
|
|
37 |
+ |
assert!(
|
|
38 |
+ |
stderr.contains("ssh -t"),
|
|
39 |
+ |
"the message does not say what to do about it:\n{stderr}",
|
|
40 |
+ |
);
|
|
41 |
+ |
assert!(
|
|
42 |
+ |
!stderr.contains("panicked"),
|
|
43 |
+ |
"still panicking rather than reporting:\n{stderr}",
|
|
44 |
+ |
);
|
|
45 |
+ |
}
|