diff --git a/src/exec.rs b/src/exec.rs index f1d04cc..4306e92 100644 --- a/src/exec.rs +++ b/src/exec.rs @@ -149,7 +149,10 @@ async fn run_script( /// Execute a full input line. `proc` is the shell's process — cd modifies it. /// Returns (exit_code, should_exit). pub async fn execute(os: Arc, proc: &mut Process, input: &str) -> (i32, bool) { - let result = if input.contains('\n') { + let result = if proc.max_input > 0 && input.len() > proc.max_input { + proc.err_msg("strands-shell: input too large"); + (1, false) + } else if input.contains('\n') { execute_sourced(os.clone(), proc, input).await } else { execute_with_reader(os.clone(), proc, input, &mut |_| None).await diff --git a/tests/shell_integration.rs b/tests/shell_integration.rs index 440cd01..62702c4 100644 --- a/tests/shell_integration.rs +++ b/tests/shell_integration.rs @@ -4252,6 +4252,26 @@ fn builder_max_input() { })); } +#[test] +fn max_input_applies_to_whole_multiline_input() { + let (rt, local) = rt(); + rt.block_on(local.run_until(async { + let mut shell = Shell::builder().max_input(16).build().unwrap(); + // Each line is under the limit, but the whole input is not + let out = shell.run("echo aaaa\necho bbbb\necho cccc").await; + assert_eq!( + (out.status, out.stdout.as_str(), out.stderr.as_str()), + (1, "", "strands-shell: input too large\n") + ); + // Multiline input within the limit still runs + let out = shell.run("echo a\necho b").await; + assert_eq!( + (out.status, out.stdout.as_str(), out.stderr.as_str()), + (0, "a\nb\n", "") + ); + })); +} + #[test] fn builder_max_file_size() { let (rt, local) = rt(); @@ -4427,17 +4447,24 @@ fn max_output_truncates_subst() { fn max_input_in_subst() { let (rt, local) = rt(); rt.block_on(local.run_until(async { - // The top-level command is `cat <