Skip to content

Commit 2cb06f6

Browse files
author
Greyforge Admin
committed
Handle logout confirmation read errors
1 parent 7954d02 commit 2cb06f6

2 files changed

Lines changed: 62 additions & 5 deletions

File tree

src/cortex-cli/src/login.rs

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use cortex_login::{
77
safe_format_key, save_auth_with_fallback,
88
};
99
use std::collections::HashSet;
10-
use std::io::{IsTerminal, Read};
10+
use std::io::{BufRead, IsTerminal, Read};
1111
use std::path::PathBuf;
1212

1313
/// Check for duplicate config override keys and warn the user.
@@ -41,6 +41,14 @@ fn get_cortex_home() -> PathBuf {
4141
})
4242
}
4343

44+
/// Read and parse a logout confirmation response.
45+
pub fn read_logout_confirmation<R: BufRead>(reader: &mut R) -> std::io::Result<bool> {
46+
let mut input = String::new();
47+
reader.read_line(&mut input)?;
48+
let input = input.trim().to_lowercase();
49+
Ok(input == "y" || input == "yes")
50+
}
51+
4452
/// Run login with API key.
4553
pub async fn run_login_with_api_key(config_overrides: CliConfigOverrides, api_key: String) -> ! {
4654
check_duplicate_config_overrides(&config_overrides);
@@ -205,13 +213,18 @@ pub async fn run_logout(config_overrides: CliConfigOverrides, skip_confirmation:
205213
);
206214
let _ = std::io::Write::flush(&mut std::io::stderr());
207215

208-
let mut input = String::new();
209-
if std::io::stdin().read_line(&mut input).is_ok() {
210-
let input = input.trim().to_lowercase();
211-
if input != "y" && input != "yes" {
216+
let stdin = std::io::stdin();
217+
let mut stdin = stdin.lock();
218+
match read_logout_confirmation(&mut stdin) {
219+
Ok(true) => {}
220+
Ok(false) => {
212221
print_info("Logout cancelled.");
213222
std::process::exit(0);
214223
}
224+
Err(e) => {
225+
print_error(&format!("Failed to read logout confirmation: {e}"));
226+
std::process::exit(1);
227+
}
215228
}
216229
}
217230
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
use std::io::{self, BufRead, Cursor, Read};
2+
3+
use cortex_cli::login::read_logout_confirmation;
4+
5+
struct FailingReader;
6+
7+
impl Read for FailingReader {
8+
fn read(&mut self, _buf: &mut [u8]) -> io::Result<usize> {
9+
Err(io::Error::other("stdin unavailable"))
10+
}
11+
}
12+
13+
impl BufRead for FailingReader {
14+
fn fill_buf(&mut self) -> io::Result<&[u8]> {
15+
Err(io::Error::other("stdin unavailable"))
16+
}
17+
18+
fn consume(&mut self, _amt: usize) {}
19+
}
20+
21+
#[test]
22+
fn logout_confirmation_accepts_yes_values() {
23+
let mut lowercase = Cursor::new(b"yes\n");
24+
assert!(read_logout_confirmation(&mut lowercase).unwrap());
25+
26+
let mut uppercase = Cursor::new(b"Y\n");
27+
assert!(read_logout_confirmation(&mut uppercase).unwrap());
28+
}
29+
30+
#[test]
31+
fn logout_confirmation_rejects_empty_or_negative_values() {
32+
let mut empty = Cursor::new(b"\n");
33+
assert!(!read_logout_confirmation(&mut empty).unwrap());
34+
35+
let mut no = Cursor::new(b"no\n");
36+
assert!(!read_logout_confirmation(&mut no).unwrap());
37+
}
38+
39+
#[test]
40+
fn logout_confirmation_propagates_read_errors() {
41+
let mut reader = FailingReader;
42+
let error = read_logout_confirmation(&mut reader).unwrap_err();
43+
assert_eq!(error.kind(), io::ErrorKind::Other);
44+
}

0 commit comments

Comments
 (0)