Skip to content

Commit 991da40

Browse files
factorydroidechobt
authored andcommitted
fix(cli): validate whitespace-only prompts before quote-wrapping
Fixes bounty issue #1497 When a user provides a whitespace-only prompt like `cortex run " "`, the message was wrapped in quotes before validation, causing the validation check to pass because the trimmed string contained quote characters. This allowed whitespace-only prompts to be sent to the engine, causing hangs or empty streams. The fix validates the original message content before quote-wrapping is applied, properly catching whitespace-only prompts and returning a validation error.
1 parent b963993 commit 991da40

1 file changed

Lines changed: 30 additions & 2 deletions

File tree

cortex-cli/src/run_cmd.rs

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -253,6 +253,10 @@ impl RunCli {
253253
bail!("top-p must be between 0.0 and 1.0, got {top_p}");
254254
}
255255

256+
// Check if original message args are all whitespace (before quote-wrapping)
257+
// This catches cases like `cortex run " "` which would otherwise pass validation
258+
let message_args_all_whitespace = self.message.iter().all(|s| s.trim().is_empty());
259+
256260
// Build the message from arguments
257261
let mut message = self
258262
.message
@@ -268,10 +272,12 @@ impl RunCli {
268272
.join(" ");
269273

270274
// Read from stdin if not a TTY (piped input)
275+
let mut has_stdin_content = false;
271276
if !io::stdin().is_terminal() {
272277
let mut stdin_content = String::new();
273278
io::stdin().lock().read_to_string(&mut stdin_content)?;
274-
if !stdin_content.is_empty() {
279+
if !stdin_content.trim().is_empty() {
280+
has_stdin_content = true;
275281
if !message.is_empty() {
276282
message.push('\n');
277283
}
@@ -280,7 +286,8 @@ impl RunCli {
280286
}
281287

282288
// Validate we have something to do
283-
if message.trim().is_empty() && self.command.is_none() {
289+
// Use the pre-quote-wrap check for message args to catch whitespace-only prompts
290+
if message_args_all_whitespace && !has_stdin_content && self.command.is_none() {
284291
bail!("You must provide a message or a --command");
285292
}
286293

@@ -980,4 +987,25 @@ mod tests {
980987
assert!(!(0.0..=2.0).contains(&-0.1));
981988
assert!(!(0.0..=2.0).contains(&2.1));
982989
}
990+
991+
#[test]
992+
fn test_whitespace_only_message_detection() {
993+
// Test that whitespace-only messages are detected before quote-wrapping
994+
let whitespace_args = vec![" ".to_string()];
995+
assert!(whitespace_args.iter().all(|s| s.trim().is_empty()));
996+
997+
let whitespace_args2 = vec![" ".to_string(), "\t".to_string()];
998+
assert!(whitespace_args2.iter().all(|s| s.trim().is_empty()));
999+
1000+
// Test that non-whitespace messages are not detected as whitespace
1001+
let valid_args = vec!["hello".to_string()];
1002+
assert!(!valid_args.iter().all(|s| s.trim().is_empty()));
1003+
1004+
let mixed_args = vec![" ".to_string(), "hello".to_string()];
1005+
assert!(!mixed_args.iter().all(|s| s.trim().is_empty()));
1006+
1007+
// Test empty message args
1008+
let empty_args: Vec<String> = vec![];
1009+
assert!(empty_args.iter().all(|s| s.trim().is_empty()));
1010+
}
9831011
}

0 commit comments

Comments
 (0)